隐式分辨与逆变

给定父类和子类。

scala> class Parent
defined class Parent

scala> class Child extends Parent
defined class Child

定义Parent和Child的含义

scala> implicit val a = new Parent
a: Parent = Parent@5902f207

scala> implicit val b = new Child
b: Child = Child@3f7d8bac

implicitly使用来找出哪些隐式被解析。

scala> implicitly[Child] 
res1: Child = Child@3f7d8bac

我的理解的插图:

         Parent
           |
         Child -- implicit resolution gets the most specific, lowest sub-type

现在,让我们使用逆变类型。

scala> trait A[-T]
defined trait A

scala> case class Concrete[T]() extends A[T]
defined class Concrete

然后定义一个Parent和Child类。

scala> class Parent
defined class Parent

scala> class Kid extends Parent
defined class Kid

也为他们创建暗示。

scala> implicit val x = Concrete[Parent]
x: Concrete[Parent] = Concrete()

scala> implicit val y = Concrete[Kid]
y: Concrete[Kid] = Concrete()

scala> implicitly[A[Parent]]
res1: A[Parent] = Concrete()

scala> implicitly[A[Kid]]
    <console>:21: error: ambiguous implicit values:
     both value x of type => Concrete[Parent]
     and value y of type => Concrete[Kid]
     match expected type A[Kid]
                  implicitly[A[Kid]]
                        ^

在第一个例子(没有逆变),斯卡拉是能够解决的隐含Childimplicitly[Parent] 。 在我看来,它选择最低的子类型。

但是,使用contravariance ,行为会发生变化。 为什么?


你的含义是键入Concrete ,这是不变的。

试一试

case class Concrete[-T]() extends A[T]

要么

implicit val x: A[Parent] = Concrete[Parent]

更多词语:

Implicits(值或视图)应该有一个明确的类型,所以你从不会对推断的类型感到惊讶。 隐含的选择全是关于类型的。

它使用与重载解析转换相同的规则来选择一个隐含条件,用于选择重载符号的替代选项。

对于简单的值(不是函数调用),归结为一致性或子类型。

还有一个规则是“派生类型”(通常是一个子类)中的定义是首选。

以下是您只能使用常用家用材料进行的测试:

scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'.          **
** scala.tools.nsc._ has been imported      **
** global._, definitions._ also imported    **
** Try  :help, :vals, power.<tab>           **

scala> trait A[-T]
defined trait A

scala> case class Concrete[T](i: Int) extends A[T]
defined class Concrete

scala> class Parent ; class Kid extends Parent
defined class Parent
defined class Kid

// it will pick X if X isAsSpecific as Y but not conversely
scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]])
res0: Boolean = false

scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]])
res1: Boolean = false

scala> case class Concrete[-T](i: Int) extends A[T]
defined class Concrete

scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]])
res2: Boolean = false

scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]])
res3: Boolean = true

编辑:

关于为什么它关系你正在测试什么类型的另一种观点:

scala> trait A[-T]
defined trait A

scala> case class Concrete[T](i: Int) extends A[T]  // invariant
defined class Concrete

scala> class Parent ; class Kid extends Parent
defined class Parent
defined class Kid

scala> implicitly[Concrete[Parent] <:< Concrete[Kid]]
<console>:13: error: Cannot prove that Concrete[Parent] <:< Concrete[Kid].
              implicitly[Concrete[Parent] <:< Concrete[Kid]]
                        ^

scala> implicit val x: Concrete[Parent] = Concrete[Parent](3)  // the inferred type
x: Concrete[Parent] = Concrete(3)

scala> implicit val y  = Concrete[Kid](4)
y: Concrete[Kid] = Concrete(4)

// both values conform to A[Kid] (because A is contravariant)
// but when it puts x and y side-by-side to see which is more specific,
// it no longer cares that you were looking for an A.  All it knows is
// that the values are Concrete.  The same thing happens when you overload
// a method; if there are two candidates, it doesn't care what the expected
// type is at the call site or how many args you passed.

scala> implicitly[A[Kid]]
<console>:15: error: ambiguous implicit values:
 both value x of type => Concrete[Parent]
 and value y of type => Concrete[Kid]
 match expected type A[Kid]
              implicitly[A[Kid]]
                        ^

给他们明确的类型,混凝土的方差并不重要。 你总是为你的暗示提供显式类型,对吧? 就像retronym告诉我们的?

scala> implicit val x: A[Parent] = Concrete[Parent](3)
x: A[Parent] = Concrete(3)

scala> implicit val y: A[Kid] = Concrete[Kid](4)
y: A[Kid] = Concrete(4)

scala> implicitly[A[Kid]]
res2: A[Kid] = Concrete(3)
链接地址: http://www.djcxy.com/p/77575.html

上一篇: Implicit Resolution with Contravariance

下一篇: Keep UIKeyboard with view when swiping back iOS 7