Scala 为什么类型推断在查看隐式转换时只选择最特定的目标引用类型?
考虑下面的简单代码来创建类型安全的equals。第一部分允许我为任何类型创建一个Scala 为什么类型推断在查看隐式转换时只选择最特定的目标引用类型?,scala,type-inference,typeclass,Scala,Type Inference,Typeclass,考虑下面的简单代码来创建类型安全的equals。第一部分允许我为任何类型创建一个Identitytypeclass scala> trait Equals[A] { def equal(a1 : A, a2 : A) : Boolean } defined trait Equals scala> sealed trait Identity[A] { | def value : A | def ===(b : A)(implicit e : Equals[A])
Identity
typeclass
scala> trait Equals[A] { def equal(a1 : A, a2 : A) : Boolean }
defined trait Equals
scala> sealed trait Identity[A] {
| def value : A
| def ===(b : A)(implicit e : Equals[A]) = e.equal(value, b)
| }
defined trait Identity
scala> implicit def ToIdentity[A](a : A) = new Identity[A] { val value = a }
ToIdentity: [A](a: A)java.lang.Object with Identity[A]
因此,如果我为Equals[Int]
创建一个typeclass,我现在应该能够使用我的typesafe Equals:
scala> implicit val EqualsInt = new Equals[Int] { def equal(i1 : Int, i2 : Int) = i1 == i2 }
EqualsInt: java.lang.Object with Equals[Int] = $anon$1@7e199049
scala> 1 === 2
res1: Boolean = false
scala> 1 === 1
res2: Boolean = true
scala> 1 === 1D
<console>:10: error: type mismatch;
found : Double(1.0)
required: Int
1 === 1D
^
但是如果我告诉编译器我的类型是Any
,而不是Int
scala> (1 : Any) === 1D
res6: Boolean = true
所以我的问题是“为什么编译器不考虑1逻辑上具有的所有类型?”
也就是说,我的理解是Int
类型的引用在逻辑上具有Int
、AnyVal
和Any
类型。无论如何,我探索了更多,假设问题与协方差有关。我更改了我对身份的定义:
scala> sealed trait Identity[+A] {
| def value : A
| def ===[B >: A : Equals](b : B) = implicitly[Equals[B]].equal(value, b)
| }
defined trait Identity
这次我得到了一个错误:
scala> 1 === 1D
<console>:10: error: could not find implicit value for evidence parameter of type Equals[AnyVal]
1 === 1D
^
所以这里我假设问题在于等于的非逆变。所以我再试一次(但不创建等于[AnyVal]
):
所以,我可以看到打字机在这里做什么。但是我的问题看起来是这样的:为什么打字机没有问这个问题(我的第一个例子):
1是一个Int
;使用implicits in作用域,我可以创建一个标识[Int]
,然后使用=
方法。但这不起作用,因为参数不是Int
。请考虑1的备用类型,然后重试
1是一个AnyVal
;使用implicits in作用域,我可以创建一个标识[AnyVal]
,然后使用==
。但这不起作用,因为尽管参数是AnyVal
,但范围中没有隐式的等于[AnyVal]
。请考虑1的备用类型,然后重试
1是一个任意;使用implicits in作用域,我可以创建一个标识[Any]
,然后使用==
。这是因为两个参数都是Any
,并且范围中有一个等于[Any]
为什么类型推理只考虑最严格的1(即Int)类型?
< P>你所看到的是优先级的隐式转换,在Scala 2.8中添加。
根据(pdf)第7.2节:
如果有多个符合条件的参数与隐式
参数的类型,将使用规则选择最具体的类型
静态过载分辨率(§6.26.3)
这也是支持从中构建行为的机制。你能对此进行扩展吗,可能参考语言规范?至于为什么这有意义:想象一下如果你总是转换为最通用的类型会发生什么…@Raphael-但我的观点是,你会选择最具体的,然后,如果这没有带来成功的结果,那么尝试下一个最具体的方法。在邮件列表上,Martin Odersky的回答基本上是“这是因为这样做会在计算上花费太多”希望你不反对我链接到你的另一个问题:)
scala> 1 === 1D
<console>:10: error: could not find implicit value for evidence parameter of type Equals[AnyVal]
1 === 1D
^
scala> implicit val EqualsAnyVal = new Equals[AnyVal] { def equal(a1 : AnyVal, a2 : AnyVal) = a1 == a2 }
EqualsAnyVal: java.lang.Object with Equals[AnyVal] = $anon$1@67ce08c7
scala> 1 === 1D
res4: Boolean = true
scala> trait Equals[-A] { def equal(a1 : A, a2 : A) : Boolean }
defined trait Equals
scala> 1 === 1D
res3: Boolean = true