Map("name" -> "foo")
は関数呼び出しであり、コンストラクターではありません。これは、次のように記述できないことを意味します。
Map("name" -> "foo") with MoreFilterOperations
あなたが書くことができる以上
val m = Map("name" -> "foo")
val m2 = m with MoreFilterOperations
ミックスインを取得するには、具象型を使用する必要があります。単純な最初の試みは次のようになります。
def EnhMap[K,V](entries: (K,V)*) =
new collection.immutable.HashMap[K,V] with MoreFilterOptions[(K,V)] ++ entries
ここでファクトリ メソッドを使用して、型パラメータを複製する必要がないようにします。ただし、メソッドはmixin なしで++
単純な古い を返すだけなので、これは機能しません!HashMap
解決策 (サムが提案したように) は、暗黙的な変換を使用して pimped メソッドを追加することです。これにより、すべての通常の手法でマップを変換し、結果のマップで追加のメソッドを使用することができます。コンストラクターのパラメーターを使用できるようにすると、よりクリーンな構文になるため、通常はこれをトレイトではなくクラスで行います。
class MoreFilterOperations[T](t: Traversable[T]) {
def filterFirstTwo(f: (T) => Boolean) = t filter f take 2
}
object MoreFilterOperations {
implicit def traversableToFilterOps[T](t:Traversable[T]) =
new MoreFilterOperations(t)
}
これにより、次のように書くことができます
val m = Map("name"->"foo", "name2"->"foo2", "name3"->"foo3")
val m2 = m filterFirstTwo (_._1.startsWith("n"))
しかし、コレクション フレームワークではまだうまく機能しません。マップから始めて、Traversable
. それは物事がうまくいくはずの方法ではありません。ここでの秘訣は、高種類の型を使用してコレクション型も抽象化することです
import collection.TraversableLike
class MoreFilterOperations[Repr <% TraversableLike[T,Repr], T] (xs: Repr) {
def filterFirstTwo(f: (T) => Boolean) = xs filter f take 2
}
十分に単純です。コレクションをRepr
表す型である とT
、要素の型である を指定する必要があります。その表現を埋め込むTraversableLike
代わりに使用します。Traversable
これがないと、開始タイプに関係なくfilterFirstTwo
a が返されます。Traversable
次に、暗黙の変換です。ここで、型表記がややこしくなります。まず、コレクションの表現をキャプチャするために高次の型を使用しています: CC[X] <: Traversable[X]
、これは型をパラメーター化します。これCC
は Traversable のサブクラスでなければなりません (X
ここでのプレースホルダーとしてのの使用CC[_] <: Traversable[_]
は同じことを意味しないことに注意してください)。
また、コンパイラがコレクションが本当に のサブクラスであり、コンストラクタの有効な引数であるCC[T] <:< TraversableLike[T,CC[T]]
ことを静的に保証するために使用するimplicit もあります。CC[T]
TraversableLike
MoreFilterOperations
object MoreFilterOperations {
implicit def traversableToFilterOps[CC[X] <: Traversable[X], T]
(xs: CC[T])(implicit witness: CC[T] <:< TraversableLike[T,CC[T]]) =
new MoreFilterOperations[CC[T], T](xs)
}
ここまでは順調ですね。しかし、まだ 1 つの問題があります.2 つの型パラメーターを取るため、マップでは機能しません。MoreFilterOperations
解決策は、以前と同じ原則を使用して、別の暗黙的なオブジェクトをオブジェクトに追加することです。
implicit def mapToFilterOps[CC[KX,VX] <: Map[KX,VX], K, V]
(xs: CC[K,V])(implicit witness: CC[K,V] <:< TraversableLike[(K,V),CC[K,V]]) =
new MoreFilterOperations[CC[K,V],(K,V)](xs)
本当の美しさは、実際にはコレクションではないが、コレクションであるかのように表示できる型を操作したい場合に現れます。コンストラクターのRepr <% TraversableLike
を覚えていますか? MoreFilterOperations
これはビュー バウンドであり、暗黙的に変換できる型とTraversableLike
直接のサブクラスを許可します。文字列はこの典型的な例です:
implicit def stringToFilterOps
(xs: String)(implicit witness: String <%< TraversableLike[Char,String])
: MoreFilterOperations[String, Char] =
new MoreFilterOperations[String, Char](xs)
REPL で実行する場合:
val m = Map("name"->"foo", "name2"->"foo2", "name3"->"foo3")
// m: scala.collection.immutable.Map[java.lang.String,java.lang.String] =
// Map((name,foo), (name2,foo2), (name3,foo3))
val m2 = m filterFirstTwo (_._1.startsWith("n"))
// m2: scala.collection.immutable.Map[java.lang.String,java.lang.String] =
// Map((name,foo), (name2,foo2))
"qaxfwcyebovjnbointofm" filterFirstTwo (_ < 'g')
//res5: String = af
地図が入り、地図が出てきます。弦が入り、弦が出ます。等...
、 、 、またはで試したことはStream
まだありませんが、試した場合は、最初に使用したのと同じタイプのコレクションが返されると確信できます。Set
Vector