Scala 为什么类型推断在查看隐式转换时只选择最特定的目标引用类型?

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])

考虑下面的简单代码来创建类型安全的equals。第一部分允许我为任何类型创建一个
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