8

これは私を悩ませます:

trait Foo[A]
class Bar[A](set: Set[Foo[A]] = Set.empty)

これにより、

<console>:8: error: polymorphic expression cannot be instantiated to expected type;
 found   : [A]scala.collection.immutable.Set[A]
 required: Set[Foo[?]]
       class Bar[A](set: Set[Foo[A]] = Set.empty)
                                           ^

で type パラメータを繰り返さなければならないのは非常に面倒ですSet.empty。このデフォルト引数で型推論が失敗するのはなぜですか? 以下の作品:

class Bar[A](set: Set[Foo[A]] = { Set.empty: Set[Foo[A]] })

Setこれは特に何の関係もないことに注意してください:

case class Hallo[A]()
class Bar[A](hallo: Hallo[A] = Hallo.apply)  // nope

奇妙なことに、これが機能するだけではありません:

class Bar[A](hallo: Hallo[A] = Hallo.apply[A])

...しかし、これも:

class Bar[A](hallo: Hallo[A] = Hallo())      // ???
4

1 に答える 1

6

empty余分な中括弧/中括弧と型アノテーションのセットを追加する必要はなく、メソッドで直接型を指定できます。

class Bar[A]( set: Set[Foo[A]] = Set.empty[Foo[A]] )

型推論が失敗する理由については、次の質問を参照してください。

アップデート:

申し訳ありませんが、急いで答えるのはかなり遠いものでした。上記の投稿の問題は、実際にはこの問題とは関係ありません。@TravisBrownは、上記のコメントで非常に良い点を指摘しました。これは最初は機能しているようです。

class Bar[A]( set: Set[A] = Set.empty )

しかし、実際にコンストラクターを呼び出そうとすると、use-siteで失敗します。

new Bar[Int]
//  <console>:9: error: type mismatch;
//   found   : scala.collection.immutable.Set[Nothing]
//   required: Set[Int]
//  Note: Nothing <: Int, but trait Set is invariant in type A.
//  You may wish to investigate a wildcard type such as `_ <: Int`. (SLS 3.2.10)
//  Error occurred in an application involving default arguments.
//                new Bar[Int]

これは、コンパイラがデフォルトパラメータをすべてに対して有効にするのAではなく、一部に対してのみ有効であることを示していますA。彼らはおそらくあなたがこのようなことをすることができるようにその選択をしました:

scala> case class MyClass[T](set: Set[T] = Set(0))
defined class MyClass

scala> MyClass() // defaults to MyClass[Int]
res0: MyClass[Int] = MyClass(Set(0))

scala> MyClass(Set('x)) // but I can still use other types manually
res1: MyClass[Symbol] = MyClass(Set('x))

ただし、パラメーター化された型を使用したあらゆる種類のネストは、コンストラクターの宣言サイトでの型チェックに失敗します。

class Bar[A]( set: Set[Option[A]] = Set.empty )
// <console>:7: error: polymorphic expression cannot be instantiated to expected type;
//  found   : [A]scala.collection.immutable.Set[A]
//  required: Set[Option[?]]
//        class Bar[A]( set: Set[Option[A]] = Set.empty )

タイプパラメータが共変位置にある場合、推論は失敗しません。

class Bar[ A ]( set: List[Foo[A]] = List.empty ) // OK

class Bar[ A ]( set: Map[Int,Foo[A]] = Map.empty ) // OK (unless you use it)

class Bar[ A ]( set: Map[Foo[A],Int] = Map.empty ) // BAD
// <console>:8: error: polymorphic expression cannot be instantiated to expected type;
//  found   : [A, B]scala.collection.immutable.Map[A,B]
//  required: Map[Foo[?],Int]
//            class Bar[ A ]( set: Map[Foo[A],Int] = Map.empty ) // BAD
//                                                       ^

Nothingコンパイラがデフォルトで共変型として選択するため、これらは機能しています。これはに対しては正常に機能Listしますが、実際に呼び出そうとすると、上記の2番目の例は機能しません。

この奇妙さのほとんどの原因は、おそらくScalaがデフォルトの引数を処理する方法です。コンパイラはコンパニオンオブジェクトに追加のメソッドを自動的に追加し、引数を省略した場合は常に、コンパイラはコンパニオンオブジェクトの新しいメソッドにメソッド呼び出しを自動的に追加して、欠落している引数を生成します。デフォルトの引数をメソッドに抽象化すると、通常の割り当てで機能する型推論の一部が壊れているように見えます。

これらの調査結果のほとんどはかなり紛らわしいと思います。これから私が奪うのは、デフォルトのパラメーターを実際にテストして、それらを使用しようとしたときにタイプの正確性が損なわれないことを確認することが重要であるということです。

于 2012-10-28T17:48:56.817 に答える