2014-09-10 138 views
16

假設我有一個簡單的類型類,其實例會給我一些類型的值:從實例創建一個協變型類的實例非協變一個

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,但可能是我錯過了一些東西。這有意義嗎?有沒有合理的解決方法?

回答

2

我不明白爲什麼它的工作,但下面的代碼在當前情況下(至少在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