2012-03-31 9 views
2

私は今やscalaを使っていますが、私は実際にすべてを理解し始めていると思っていました。私は自分自身がMapクラスのいくつかのメソッド定義で混乱しているのを見つけました。私はfoldLeftなどの仕組みが分かっていますが、私が混乱しているのはMap関数で使用される型パラメータです。のは、一例としてfoldLeft使用してみましょう:特性/クラス型のパラメータが優先されるときのルールとメソッド型のパラメータ

foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B 

マップ形質自体の定義は、2つのタイプのパラメータ「A」および「B」(例えば地図[A + B])をとります。クラス/特性の型パラメータの1つと同じ名前を使用してメソッドの型パラメータを定義すると、クラス/特性値が上書きされます。例としてはFooのこの定義を取る:

class Foo[A : Manifest, B : Manifest] { 
    def isAString() = manifest[A] == manifest[String] 
    def isAInt() = manifest[A] == manifest[Int] 
    def isBString() = manifest[B] == manifest[String] 
    def isBInt() = manifest[B] == manifest[Int] 
    def nowIsBString[B : Manifest] = manifest[B] == manifest[String] 
} 

scala> val f = new Foo[String,Int] 
f: Foo[String,Int] = [email protected] 

scala> f.isAString 
res290: Boolean = true 

scala> f.isAInt 
res291: Boolean = false 

scala> f.isBString 
res292: Boolean = false 

scala> f.isBInt 
res293: Boolean = true 

scala> f.nowIsBString[String] 
res294: Boolean = true 

scala> f.nowIsBString[Int] 
res295: Boolean = false 

だからfoldLeft定義で、「B」はメソッドの定義から来て、「A」はトレイトの定義から来ています。たとえば、次のように

val xm = Map("test" -> 1, "test2" -> 2) 

scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2 
foldFn: (Int, (String, Int)) => Int = <function2> 

scala> m.foldLeft(0)(foldFn) 
res298: Int = 3 

私はintの代わりに文字列への機能のために「B」タイプを変更すると、これはと形質の機能マッチ「B」は「B」が、何として期待されています

scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2 
foldFn: (String, (String, String)) => java.lang.String = <function2> 

scala> m.foldLeft("")(foldFn) 
<console>:19: error: type mismatch; 
found : (String, (String, String)) => java.lang.String 
required: (java.lang.String, (java.lang.String, Int)) => java.lang.String 
       m.foldLeft("")(foldFn) 

それでは、(文字列、INT)にKVパラメータを変更してみましょう:

scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2 
foldFn: (String, (String, Int)) => java.lang.String = <function2> 

scala> m.foldLeft("")(foldFn) 
res299: java.lang.String = 12 

私はFooの例とは異なり、この場合には地図の「B」値は、関数の定義より優先して、だけのためでありますkvパラメータ私は何を期待しているだろうことは、次のように定義されたfoldLeftを確認することです。私にはより明確になり

foldLeft[C] (z: C)(op: (C, (A, B)) => C): C 

を、それはこのように定義されていません。では、メソッドのパラメータがtrait/classパラメータをオーバーライドするときのルールを知っていますか?

+1

何らかの理由で私は投稿後に私の質問に答えを見つけるようだ:) http://stackoverflow.com/questions/8397684/type-parameter-of-minbybf-ab-bimplicit-cmp-orderingb-abしかし、これがいつ発生したのかを知るためのルールがあるかどうかは知りたいです。 – Mike

+0

'foldLeft'が' TraversableOnce'で定義されています。 'A'パラメータは' TraversableOnce'のパラメータであり、 'Map'のパラメータではありません。 –

答えて

1

Scalaはこの点でJavaと同じであり、the Java specificationの「名称」の章で以下が適用される:

命名型の宣言D N影任意の宣言DDの範囲全体 を発生時点でスコープ内にあるN名前 他のタイプ。

したがって、メソッドのtypeパラメータは、同じ名前のクラスまたはtrait型パラメータを常にシャドウします。あなたのFooの例がこの事実を示しています。

あなたがリンクした質問への回答でpointed outがあるとして、あなたがMapfoldLeftの場合には見ている明白な反例は、ちょうどan unpleasant artifact Scaladocの現在のバージョンのです。 foldLeftは、Mapの形質では定義されていませんが、Bという名前の形質型のパラメータが存在しないTraversableOnceには定義されていません。

一般に、メソッド内の特性またはクラスの型パラメータをシャドーイングすることは、本当に悪い考えです。

関連する問題