13

次の 2 つの特性があるとします。

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

そして、2 番目から 1 番目への暗黙的な変換:

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

Barと整数のリストを作成します。

val bar = new Bar {}
val stuff = List(1, 2, 3)

今、私は次のように動作することを期待しています:

bar howMany stuff

しかし、そうではありません:

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff
                          ^

そこで、specに移動します。これには次のように書かれています (太字の強調は私のものです)。

ビューは 3 つの状況で適用されます。

  1. 【ここは関係ない】

  2. タイプTeを持つ選択em、セレクターmがTのメンバーを示さない場合。この場合、eに適用可能で、その結果にmという名前のメンバーが含まれるビューvが検索されます。検索は、暗黙のパラメーターの場合と同様に進行します。ここで、暗黙のスコープはTのスコープです。そのようなビューが見つかった場合、選択emはv(e).mに変換されます。

  3. タイプTのeを持つ選択em(args)、セレクターmがTの一部のメンバーを示しているが、これらのメンバーのいずれも引数argsに適用できない場合。この場合、eに適用可能なビューvが検索され、その結果にはargs に適用可能なメソッドmが含まれます。検索は、暗黙のパラメーターの場合と同様に進行します。ここで、暗黙のスコープはTのスコープです。そのようなビューが見つかった場合、選択emはv(e).m(args)に変換され ます。

そこで、私たちは次のことを試みます。

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar { def howMany = throw new Exception("I don't do anything!") }

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

ただし、(少なくとも 2.9.2 と 2.10.0-RC2 の両方で):

scala> bar howMany stuff
res0: Int = 3

これは、この問題の回避策の例のように、いくつかの非常に奇妙な動作につながります。

3 つの (密接に関連する) 質問があります。

  1. 上記の元のケースでビューを正しく適用する簡単な方法 (つまり、適切な名前で偽のメソッドを追加する必要がない方法) はありますか?
  2. 誰かがこの動作を説明する仕様の読みを提供できますか?
  3. これが意図された動作であると仮定すると、まったく意味がありますか?

また、この問題に関する以前の議論へのリンクもあれば幸いです。Google とのやり取りはあまりうまくいきませんでした。

4

5 に答える 5

1

皆様のご参考までに、これは単なるバグである可能性があります。あなたがそれを知っている方法はエラーメッセージです:

<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]

List[A] は実際の型ではありません - それ自身の型パラメータに適用された List です。それは表現できる型ではないので、要求できる型ではありません。

[編集 - 私が何について話しているのか誰にもわからないので、まだ時期尚早です。上記は無視してください。ただし、リンクをたどることはできます。]

これに関連するチケットはhttps://issues.scala-lang.org/browse/SI-6472です。

于 2012-12-06T17:26:46.587 に答える
1

これはバグのように思えるので、私の答えは次のとおりです。

  1. Scala コンパイラーに対して報告された類似のバグを検索し、見つからない場合は、新しいバグを報告してください https://issues.scala-lang.org/
  2. 仕様のその部分は、型推論について話していないため、この場合は重要ではないようです
  3. 私には意味がありません

PS。2.8.1 では、ダミー メソッドを Bar に追加するという回避策ではコンパイルされません。

于 2012-11-22T18:07:55.360 に答える
0

あなたの暗黙的な変換は、あなたが言ったことを正確に行っているようです。

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

Bar を新しいFoo[A]オブジェクトに変換します。だから順番に

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff

「A」タイプを探します。

これをあなたが望むように機能させるために(私は思う)、特性のビューを定義する代わりに、関数でそれを行うことができます。

trait Foo { def howMany[A](xs: List[A]) = xs.size }
trait Bar
implicit def bar2foo[A](bar: Bar) = new Foo{}
val bar = new Bar {}
val stuff = List(1, 2, 3)

そうすれば、あなたが望む結果が得られるはずです。

scala> bar howMany stuff
res0: Int = 3

または、暗黙的な関数でビューを定義できます

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

implicit def bar2foo[A](bar: Bar) = new Foo[Int] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

個人的には、関数で定義する方がクリーンだと思います。

于 2012-11-22T16:10:44.160 に答える
0

Foo を次のように置き換えます。

trait Foo[_] { def howMany(xs: List[_]) = xs.size }

あなたは絶対にAに興味がないので、それはうまくいきます.

于 2012-11-22T15:32:02.800 に答える
0

これは醜いですが、うまくいくようです:

(bar: Foo[Int]) howMany stuff
于 2012-11-22T20:50:26.640 に答える