何时在Scala中使用`with`作为边界类型参数而不是`<:`或`<:<`?

时间:2011-12-12 21:27:36

标签: scala

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?我正在寻找关于替代方案中细微差别的讨论。感谢。

1 个答案:

答案 0 :(得分:9)

意义完全不同。 C <: Seq[A]表示CSeq[A]的子类型,如您所知; xs: C with Seq[A]并未对C设置任何限制,但意味着xs应同时为CSeq[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])

而不是你的第三个定义,这就是链接问题的答案。