2017-05-15 6 views
11

暗黙の変換が1つのケースでは正確に動作しているが、他のケースでは正確に動作していない理由を理解しようとしています。基本的に、私はOption[T]からOption[Wrapper[T]]への暗黙的な変換を持っている、と暗黙のうちに包まれますオプションの文字列を返す関数を定義しようとしています暗黙の変換奇妙さ

case class Wrapper[T](wrapped: T) 
    trait Wrapping { implicit def wrapIt[T](x: Option[T]) = x.map(Wrapper(_)) 

    class NotWorking extends Wrapping { def foo: Option[Wrapper[String]] = Some("foo") } 

    class Working extends Wrapping { 
     def foo: Option[Wrapper[String]] = { 
     val why = Some("foo") 
     why 
     } 
    } 

: はここでの例です。

Option[String]NotWorking上記)を返そうとすると、エラー(found : String("foo") required: Wrapper[String])が返されます。結果を返す前にvalに代入すると、それはなくなります。

何がありますか?

答えて

10

これが意図されているのか、バグと思われるのか分かりませんが、ここで私は起こっていると思います。

def foo: Option[Wrapper[String]] = Some("foo")の場合、コンパイラは、Some()に提供される引数の予想される型をWrapper[String]と設定します。次に、それはあなたが期待されているものではないStringを提供していることがわかるので、暗黙の変換String => Wrapper[String]を探して見つけられず、失敗します。

なぜそれが予想されることタイプのものを必要としない、とだけ変換を見つけようその後Some[String]としてSome("foo")入力していないのですか? scalacは、次のコードです。TypeCheckできるようにしたいと考えているので:このコードが動作するためには

case class Invariant[T](t: T) 
val a: Invariant[Any] = Invariant("s") 

Invariant[String]がのサブタイプではないとして、その後、コンパイルが失敗するので、コンパイラはちょうどInvariant[String]としてInvariant("s")入力することはできませんInvariant[Any]。コンパイラは、"s"の予想タイプをAnyに設定して、"s"Anyのインスタンスであることがわかるようにする必要があります。

このコードとあなたのコードが正しく動作するためには、コンパイラには何らかのバックトラックロジックが必要なのではないかと思います。

Workingコードが機能する理由は、この種の型推論が複数の行にまたがらないためです。同様にval a: Invariant[Any] = {val why = Invariant("s"); why}ではなく、コンパイルします。