从实例创建一个协变型类的实例非协变一个

问题描述:

假设我有一个简单的类型类,其实例会给我一些类型的值:从实例创建一个协变型类的实例非协变一个

trait GiveMeJustA[X] { def apply(): X } 

而且我有一些实例:

case class Foo(s: String) 
case class Bar(i: Int) 

implicit object GiveMeJustAFoo extends GiveMeJustA[Foo] { 
    def apply() = Foo("foo") 
} 

implicit object GiveMeJustABar extends GiveMeJustA[Bar] { 
    def apply() = Bar(13) 
} 

现在我有一个类似(但不相关)Type类做同样的事情,但它的类型参数的协变:

trait GiveMeA[+X] { def apply(): X } 

在其同伴对象,我们告诉编译器如何从我们的非协变类型的类的实例创建实例:

object GiveMeA { 
    implicit def fromGiveMeJustA[X](implicit giveMe: GiveMeJustA[X]): GiveMeA[X] = 
    new GiveMeA[X] { def apply() = giveMe() } 
} 

现在我期望implicitly[GiveMeA[Foo]]编译就好了,因为有只拿到单程给予我们在这里的作品GiveMeA[Foo]。但它没有(至少不会在任2.10.4或2.11.2):

scala> implicitly[GiveMeA[Foo]] 
<console>:16: this.GiveMeA.fromGiveMeJustA is not a valid implicit value for GiveMeA[Foo] because: 
hasMatchingSymbol reported error: ambiguous implicit values: 
both object GiveMeJustAFoo of type GiveMeJustAFoo.type 
and object GiveMeJustABar of type GiveMeJustABar.type 
match expected type GiveMeJustA[X] 
       implicitly[GiveMeA[Foo]] 
         ^
<console>:16: error: could not find implicit value for parameter e: GiveMeA[Foo] 
       implicitly[GiveMeA[Foo]] 
         ^

如果我们摆脱我们无关GiveMeJustA实例,它的工作原理:

scala> implicit def GiveMeJustABar: List[Long] = ??? 
GiveMeJustABar: List[Long] 

scala> implicitly[GiveMeA[Foo]] 
res1: GiveMeA[Foo] = [email protected] 

这是尽管事实上我们无法将GiveMeA.fromGiveMeJustA应用于此实例以获得GiveMeA[Foo](或GiveMeA[Foo]的任何子类型)。

这对我来说看起来像一个bug,但可能是我错过了一些东西。这有意义吗?有没有合理的解决方法?

我不明白为什么它的工作,但下面的代码在当前情况下(至少在scala v-2.10.1)成功解析隐式。然而,这仍然无法解释为什么你的例子是不是摆在首位的工作:

我们改变隐含GiveMeA[X]实例来寻找隐含GiveMeJustA情况,其中类型参数是由X向上界,因此搜索GiveMeJustA[_ <: X]

object GiveMeA { 
    implicit def fromGiveMeJustA[X](implicit giveMe: GiveMeJustA[_ <: X]) : GiveMeA[X] = 
    new GiveMeA[X] { def apply() = giveMe() } 
} 

然后我们就可以打印出预期输出

val a = implicitly[GiveMeA[Foo]] 
println(a()) // prints "Foo(foo)" 

但是,只要我们引入了一个新的子类

case class FooChild(s: String) extends Foo(s) 

和各自GiveMeJustA类型类实例

implicit object GiveMeJustAFooChild extends GiveMeJustA[FooChild] { 
    def apply() = FooChild("fooChild") 
} 

编译器会抱怨(如预期)

error: could not find implicit value for parameter e: GiveMeA[Foo] 
    val a = implicitly[GiveMeA[Foo]] 
+0

解决方案的工作了给出的例子。但就我而言,我正在使用'Generic',其中使用了'GiveMeJustA'。在这种情况下,解决方案似乎不起作用,我猜是因为宏。 – tksfz 2016-11-29 00:15:41