简体   繁体   English

限制 function 泛型类型参数

[英]Restrict function generic type parameters

Having following structure:具有以下结构:

trait ParentType
trait ChildType extends ParentType

case class FooBar[+T <: ParentType](s: String, data: T)
object FooBar {
  def apply[T <: ChildType](i: Int, data: T): FooBar[T] = new FooBar(s"$i", data)
}
case class Foo(a: Int) extends ParentType
case class Bar(s: String) extends ChildType


def function1[T <: ParentType](obj: FooBar[T]): Unit = ()
def function2[T <: ChildType](obj: FooBar[T]): Unit = ()

Is possible(and in what way) to change the signature(with generics declaration) of function1 and function2 such that function1 can only except parameters of FooBar with type T that is direct descendant of ParentType (and prohibit any T that is direct descendant of ChildType ) and function2 in another way around - except only parameters with T that are direct descendants of ChildType and prohibit all ParentType T 's是否可以(以及以何种方式)更改function1function2的签名(使用 generics 声明),以便function1只能排除类型为TFooBar的参数,该类型是ChildType的直接后代(并禁止任何TParentType的直接后代) 和function2以另一种方式 - 除了只有带有T的参数是ChildType的直接后代并禁止所有ParentType T

In other words this shouldn't compile换句话说,这不应该编译

function1(FooBar("a", Bar("1"))) //because Bar is not direct descendant of ParentType

The question does not make very much sense, I am afraid, but to answer what you wrote in comments:恐怕这个问题没有多大意义,但要回答您在评论中写的内容:

I want function2 to accept "containers" FooBars of Mammals only我希望function2只接受哺乳动物的“容器”FooBars

So, it should be def function2(m: Foobar[Mammal])所以,它应该是def function2(m: Foobar[Mammal])

and function1 - all other group types of animals(but not mammals)和 function1 - 所有其他组类型的动物(但不是哺乳动物)

This is a weird requirement.这是一个奇怪的要求。 If you are sure you need this (I really, really doubt you actually do), I suggest something like this:如果你确定你需要这个(我真的,真的怀疑你真的需要),我建议这样:

   trait NotMammal extends Animal
   class Fish extends NotMammal
   class Reptile extends NotMammal

   ... 

   def funcction1(n: Foobar[NotMammal]) = ???

With help of @LuisMiguelMejíaSuárez (see his comments to the question) I managed to achieve what I wanted.在@LuisMiguelMejíaSuárez 的帮助下(请参阅他对问题的评论),我设法实现了我想要的。 So, taking into account as well that I need context bound for Arbitrary from scalacheck to be in these functions declarations, Luis suggestion to use shapless(in particular I found out that <:!< can solve my problem) helped因此,考虑到我需要从 scalacheck 为Arbitrary绑定的上下文在这些函数声明中,Luis 建议使用 shapless(特别是我发现<:!<可以解决我的问题)帮助

    import shapless._

    def function1[T <: ParentType](obj: FooBar[T])(implicit: arb: Arbitrary[T], ev: T <:!< ChildType): Unit = ()
    def function2[T <: ChildType : Arbitrary](obj: FooBar[T]): Unit = ()

Unfortunately I didn't manage to achieve the override of function1 (just with different ev types), but having those functions with different names I can reuse function1 from function2 (I need just to call function1 with explicit parameter for <:!< instance which is shapeless.nsub ).不幸的是,我没有设法实现对function1的覆盖(只是使用不同的ev类型),但是有了这些具有不同名称的函数,我可以从function2重用function1 (我只需要使用<:!<实例的显式参数调用function1shapeless.nsub )。

So with this solution any ChildType instance can't be applied to function1 (at least as is) because such application results in因此,使用此解决方案,任何ChildType实例都不能应用于function1 (至少按原样),因为这样的应用程序会导致

ambiguous implicit values:
 both method nsubAmbig1 in package shapeless of type [A, B >: A]A <:!< B
 and method nsubAmbig2 in package shapeless of type [A, B >: A]A <:!< B
 match expected type Bar <:!< ChildType

I guess this is what was designed behind usage of <:!< type(but if explicitly to specify an instance of <:!< it will work)我想这是使用<:!<类型背后的设计(但如果明确指定<:!<的实例,它将起作用)

Here is a link to scastie worksheet to try out the problem这是一个链接到 scastie 工作表来尝试这个问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM