在another question中,我建议在通常使用with
或<:
的地方使用<:<
。因此,不是以下列两种方式之一定义函数:
scala> def f[A,C <: Seq[A]](xs: C) = 0
f: [A, C <: scala.collection.immutable.Seq[A]](xs: C)Int
scala> f(List(1))
<console>:54: error: inferred type arguments [Nothing,List[Int]] do not conform to method f's type parameter bounds [A,C <: scala.collection.immutable.Seq[A]]
f(List(1))
^
scala> implicit def f[A,C](xs: C)(implicit ev: C <:< Seq[A]) = new { def foo = 0 }
f: [A, C](xs: C)(implicit ev: <:<[C,scala.collection.immutable.Seq[A]])java.lang.Object{def foo: Int}
scala> List(0) foo
<console>:54: error: Cannot prove that List[Int] <:< scala.collection.immutable.Seq[A].
List(0) foo
^
scala> f(List(0)) foo
res17: Int = 0
可以做到:
scala> implicit def f[A,C](xs: C with Seq[A]) = new { def foo = 0 }
f: [A, C](xs: C with scala.collection.immutable.Seq[A])java.lang.Object{def foo: Int}
scala> List(0) foo
res18: Int = 0
我的问题是:除了上述特定情况外,何时应该在类型参数上使用with
而不是<:
或<:<
?为什么不总是使用with
?我正在寻找关于替代方案中细微差别的讨论。感谢。
答案 0 :(得分:9)
意义完全不同。 C <: Seq[A]
表示C
是Seq[A]
的子类型,如您所知; xs: C with Seq[A]
并未对C
设置任何限制,但意味着xs
应同时为C
和Seq[A]
。因此,您通常应该使用您实际意思的那个。
在def f[A,C <: Seq[A]](xs: C)
中,问题是Scala的编译器无法推断A
因为它在参数类型中没有显式出现。原则上我没有看到任何理由无法推断A
;它目前没有。用C with Seq[A]
替换类型意味着A
现在出现在xs
类型中,并允许编译器推断A
。所以,如果你真的是指束缚,但要推断A
,你实际上需要写
implicit def f[A,C <: Seq[A]](xs: C with Seq[A])
而不是你的第三个定义,这就是链接问题的答案。