我正在编写
形式的函数def test[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = ...
我要求提供A
和B
类型相同的证据。
我希望test(a,a)
形式的调用可以为任何a
进行编译,但是当a
的类型涉及存在时,似乎不是这种情况,例如
case class Foo[T](c: T)
val l = List(Foo(1), Foo(1.0F), Foo(0.0)) // Inferred type: List[Foo[_ >: Double with Float with Int <: AnyVal]]
test(l.head, l.head) // Does not compile, error like: Cannot prove that Foo[_7] =:= Foo[_7].
所以我的问题是:我是否误用了=:=
?或者它可能是一个错误?或存在的基本限制?或者他们的实施限制?
我正在测试涉及依赖类型的函数f
的返回类型。
我希望它在a
中为b
和val a = f(...); val b = f(...)
返回相同的类型,因此我调用test(a, b)
。如果a
和b
的类型涉及存在,即使test(a,a)
和test(b,b)
也不会编译,如上所述。
答案 0 :(得分:3)
Implicit =:=适用于存在类型
scala> implicitly[Foo[_ <: Int] =:= Foo[_ <: Int]]
res0: =:=[Foo[_ <: Int],Foo[_ <: Int]] = <function1>
scala> implicitly[Foo[_ <: Int] =:= Foo[_]]
<console>:10: error: Cannot prove that Foo[_ <: Int] =:= Foo[_].
implicitly[Foo[_ <: Int] =:= Foo[_]]
^
问题是scala在为函数调用解析隐式时丢失了存在类型 - 这里没有推断出A和B(这就是为什么你看到_7表示并且没有发现含义)。
def test[A,B](a: A, b: B)(implicit eq: A =:= B)
可以使用类型别名来解决:
scala> case class Foo[A](a: A) {type X = A}
defined class Foo
scala> val l = List(Foo(1), Foo(1.0F), Foo(0.0)) // Inferred type: List[Foo[_ >: Double with Float with Int <: AnyVal]]
l: List[Foo[_ >: Double with Float with Int <: AnyVal]] = List(Foo(1), Foo(1.0), Foo(0.0))
scala> val k = l.head
k: Foo[_ >: Double with Float with Int <: AnyVal] = Foo(1)
scala> implicitly[k.X =:= k.X]
res15: =:=[_ >: Double with Float with Int <: AnyVal, _ >: Double with Float with Int <: AnyVal] = <function1>
scala> implicitly[k.X =:= _ >: Double with Float with Int <: AnyVal]
res16: =:=[_ >: Double with Float with Int <: AnyVal, _ >: Double with Float with Int <: AnyVal] = <function1>
但请记住,即使是具有相似签名但来自不同Foo的类型也会有所不同(因为它依赖于路径的类型) - 存在类型是如此存在!