从实例创建一个协变型类的实例非协变一个
问题描述:
假设我有一个简单的类型类,其实例会给我一些类型的值:从实例创建一个协变型类的实例非协变一个
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]]
解决方案的工作了给出的例子。但就我而言,我正在使用'Generic',其中使用了'GiveMeJustA'。在这种情况下,解决方案似乎不起作用,我猜是因为宏。 – tksfz 2016-11-29 00:15:41