5

scalaフォーラムでこの投稿に出くわしました。

ここに要約があります:

Scala コンパイラがワイルドカードの型境界を「引き継ぐ」ようには見えないことに気付きました。

scala> class Foo { def foo = 42 }
defined class Foo
scala> class Bar[A <: Foo](val a: A)
defined class Bar
scala> def bar(x: Bar[_]) = x.a.foo
:7: error: value foo is not a member of Any

メソッド bar の正確な型パラメーターはメソッドでは重要ではありませんが、メソッド bar のパラメーターは依然として Foo によって上限が設定されていると予想されます。この動作には特定の理由がありますか?

その後、議論は仕様解釈の論争に入ります:)

説明?

最終的に、ポスターはこの説明を提案します:

ただし、コンパイラが Bar[_] に対してこれを行った場合、一貫性の理由から、Bar[A] に対しても行う必要があります。ただし、後者はいくつかの奇妙な結果をもたらします。たとえば、 def bar[A](x: Bar[A], y: Bob[A]) は突然、ボブにバインドされた暗黙の型を運ぶ必要があります。Bob が独自のタイプ バインドを持っていると、非常に面倒になります。

わからない理由

def bar[A](x: Bar[A])

Bar 型パラメーターが制限されているため、単独ではコンパイルできません。

とにかく、私は次のことが完全に理にかなっていると信じています:

def bar(x: Bar[_], y : Bob[_])

回避策

彼らが提案する回避策として:

def bar(x: Bar[_ <: Foo]) = x.a.foo

DRYではないことに加えて、物事が難しくなります。

ツリーを考えてみましょう

abstract class Tree[T <: Tree[T]] { val subTree : List[T] }

ツリーを再帰的に通過する関数 (明らかに Tree クラスの外部で定義される) をどのように定義しますか。

def size( tree : Tree[_] ) = tree.subTree.size + tree.subTree.map(size(_)).sum

subTree は List[Any] に変換されるため、明らかに機能しません。そのため、型パラメーターが必要です。

def size[T <: Tree[T]]( tree : T ) = ...

さらに醜い:

class OwnATree( val myTree : Tree[_] ){}

なるはず

class OwnATree[T <: Tree[T]]( val myTree : T ){}

などなど...

どこかに何か問題があると思います:)

4

1 に答える 1

5

sizeあなたが望むものを実現する最も簡単な方法OwnATreeは、存在型を使用することです:

def size(tree: Tree[T] forSome { type T <: Tree[T] }): Int =
  tree.subTree.size + tree.subTree.map(size(_)).sum

と:

class OwnATree(val myTree: Tree[T] forSome { type T <: Tree[T] })

あなたのTree[_]バージョンでは、実際には存在型も使用されています。それらは、構文糖衣に包まれているだけです。言い換えると、

def size(tree: Tree[_]): Int = ...

以下のシンタックスシュガーです。

def size(tree: Tree[T] forSome { type T }): Int = ...

必要な制約をアンダースコア バージョンに追加することはできませんが、脱糖バージョンには追加できます。

于 2012-08-17T20:17:12.217 に答える