[解決済み】Scala 2.8 breakOut
質問
Scalaの場合
2.8
にオブジェクトがある場合、そのオブジェクトは
scala.collection.package.scala
:
def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) =
new CanBuildFrom[From, T, To] {
def apply(from: From) = b.apply() ; def apply() = b.apply()
}
という結果になると聞いたことがあります。
> import scala.collection.breakOut
> val map : Map[Int,String] = List("London", "Paris").map(x => (x.length, x))(breakOut)
map: Map[Int,String] = Map(6 -> London, 5 -> Paris)
どうなっているんだ?なぜ
breakOut
と呼ばれています。
引数として
を私の
List
?
解決方法は?
の定義に答えがあります。
map
:
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
2つのパラメータを持っていることに注意してください。ひとつはあなたの関数で、もうひとつは暗黙的なものです。もし暗黙の了解を与えなかった場合、Scala はその暗黙の了解の中で最も大きな 具体的 があります。
について
breakOut
では、何のために
breakOut
? 文字列のリストを受け取り、それぞれの文字列をタプルに変換します。
(Int, String)
を生成し、さらに
Map
を出す。そのための最も明白な方法は、中間的な
List[(Int, String)]
コレクションを作成し、それを変換します。
ということを考えると
map
を使用しています。
Builder
を省略して、結果のコレクションを生成することが可能ではないでしょうか。
List
に直接収集し、その結果を
Map
? 明らかに、そうです。しかし、そうするためには、適切な
CanBuildFrom
から
map
であり、それはまさに
breakOut
が行う。
では、その定義を見てみましょう。
breakOut
:
def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) =
new CanBuildFrom[From, T, To] {
def apply(from: From) = b.apply() ; def apply() = b.apply()
}
なお
breakOut
のインスタンスを返します。
CanBuildFrom
. たまたま、型
From
,
T
と
To
はすでに推論されています。
map
は
CanBuildFrom[List[String], (Int, String), Map[Int, String]]
. したがって
From = List[String]
T = (Int, String)
To = Map[Int, String]
最後に
breakOut
そのものです。これは
CanBuildFrom[Nothing,T,To]
. これらの型はすでにすべて知っているので、以下の型の暗黙的なものが必要だと判断できます。
CanBuildFrom[Nothing,(Int,String),Map[Int,String]]
. しかし、そのような定義はあるのでしょうか?
を見てみましょう。
CanBuildFrom
の定義です。
trait CanBuildFrom[-From, -Elem, +To]
extends AnyRef
だから
CanBuildFrom
は、その最初の型パラメータで反変数です。なぜなら
Nothing
はボトムクラス(つまり、すべてのもののサブクラス)であり、それはつまり
任意の
クラスの代わりに
Nothing
.
このようなビルダーが存在するので、Scalaはそれを使って目的の出力を生成することができます。
ビルダーについて
Scalaのコレクションライブラリの多くのメソッドは、元のコレクションを受け取り、それを何らかの方法で処理することで成り立っている(例えば
map
各要素を変換して)、その結果を新しいコレクションに格納します。
コードの再利用を最大化するために、この結果の保存は
ビルダー
(
scala.collection.mutable.Builder
これは基本的に、要素の追加と結果のコレクションの返却という2つの操作をサポートします。この結果のコレクションの型はビルダーの型に依存する。したがって
List
ビルダーは
List
, a
Map
ビルダーは
Map
といった具合です。の実装は
map
メソッドは結果の型を気にする必要はありません。ビルダーが処理してくれます。
一方、それはつまり
map
は、何らかの方法でこのビルダーを受け取る必要があります。Scala 2.8 Collectionsを設計する際に直面した問題は、どのように最良のビルダーを選択するかということでした。例えば,もし私が
Map('a' -> 1).map(_.swap)
を取得したい。
Map(1 -> 'a')
を返します。一方
Map('a' -> 1).map(_._1)
を返すことはできません。
Map
(を返します。
Iterable
).
最高のものを生み出す魔法
Builder
は、既知の式の型から、この
CanBuildFrom
暗黙のうちに
について
CanBuildFrom
何が起こっているかをよりよく説明するために、マッピングされるコレクションが
Map
ではなく
List
. に戻そう。
List
を後で確認します。とりあえず、この2つの表現について考えてみましょう。
Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)
Map(1 -> "one", 2 -> "two") map (_._2)
が返されます。
Map
を返し、2番目は
Iterable
. フィットするコレクションを返すマジックは
CanBuildFrom
. の定義について考えてみましょう。
map
を理解するために、もう一度
メソッド
map
を継承しています。
TraversableLike
. このパラメータは
B
と
That
という型パラメータを使用します。
A
と
Repr
で、これはクラスをパラメータ化するものです。両方の定義を一緒に見てみましょう。
クラス
TraversableLike
は次のように定義されています。
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
を理解するために
A
と
Repr
の定義について考えてみましょう。
Map
そのものである。
trait Map[A, +B]
extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
なぜなら
TraversableLike
を拡張するすべてのトレイトに継承されます。
Map
,
A
と
Repr
は、そのいずれからも継承される可能性があります。しかし、最後のものが優先されます。そこで、イミュータブルの定義にしたがって
Map
とそれをつなぐすべての形質が
TraversableLike
がある。
trait Map[A, +B]
extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]]
extends MapLike[A, B, This]
trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]]
extends PartialFunction[A, B] with IterableLike[(A, B), This] with Subtractable[A, This]
trait IterableLike[+A, +Repr]
extends Equals with TraversableLike[A, Repr]
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
の型パラメータを渡すと
Map[Int, String]
に渡された型は、その連鎖の下流にある
TraversableLike
で使用され、その結果
map
である。
A = (Int,String)
Repr = Map[Int, String]
例題に戻ると、最初のマップは、関数型
((Int, String)) => (Int, Int)
という型の関数を受け取り、2番目のマップは
((Int, String)) => String
. の型がタプルであるため、二重括弧を使って受信していることを強調しています。
A
を見たとおりです。
この情報をもとに、他のタイプについて考えてみましょう。
map Function.tupled(_ -> _.length):
B = (Int, Int)
map (_._2):
B = String
によって返される型は、最初の
map
は
Map[Int,Int]
であり、2番目は
Iterable[String]
. を見てみると
map
の定義から、これらの値が
That
. しかし、それらはどこから来たのでしょうか?
関係するクラスのコンパニオン・オブジェクトの内部を見ると、それらを提供するいくつかの暗黙の宣言があります。オブジェクトの
Map
:
implicit def canBuildFrom [A, B] : CanBuildFrom[Map, (A, B), Map[A, B]]
そして、オブジェクトに
Iterable
で拡張されたクラスであり、そのクラスは
Map
:
implicit def canBuildFrom [A] : CanBuildFrom[Iterable, A, Iterable[A]]
これらの定義は、パラメータ化された
CanBuildFrom
.
Scalaは、利用可能な最も具体的な暗黙の了解を選択します。最初のケースでは、それは最初の
CanBuildFrom
. 2つ目のケースでは、1つ目がマッチしなかったので、2つ目の
CanBuildFrom
.
質問に戻る
質問のコードを見てみましょう。
List
のものと
map
の定義をもう一度見て、型がどのように推論されるかを確認します。
val map : Map[Int,String] = List("London", "Paris").map(x => (x.length, x))(breakOut)
sealed abstract class List[+A]
extends LinearSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqLike[A, List[A]]
trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]]
extends SeqLike[A, Repr]
trait SeqLike[+A, +Repr]
extends IterableLike[A, Repr]
trait IterableLike[+A, +Repr]
extends Equals with TraversableLike[A, Repr]
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
のタイプは
List("London", "Paris")
は
List[String]
であるため、型
A
と
Repr
で定義された
TraversableLike
があります。
A = String
Repr = List[String]
の型は
(x => (x.length, x))
は
(String) => (Int, String)
のタイプは
B
です。
B = (Int, String)
最後の未知のタイプです。
That
の結果の型です。
map
ということで、これもすでに持っています。
val map : Map[Int,String] =
だから
That = Map[Int, String]
それはつまり
breakOut
の型またはサブタイプを返さなければなりません。
CanBuildFrom[List[String], (Int, String), Map[Int, String]]
.
関連
-
[解決済み] Scalaで定数メンバを定義するには?
-
[解決済み] NoClassDefFoundError: org/apache/hadoop/fs/StreamCapabilities (s3データをsparkで読み込む際に発生します。
-
[解決済み] SparkSQL - パーケットファイルを直接読み込む
-
[解決済み] ScalaのバージョンをScala本体から取得するにはどうしたらいいですか?
-
[解決済み] Scalaのオブジェクトとクラスの違い
-
[解決済み] Scalaのcase classとclassの違いは何ですか?
-
[解決済み】Scala 2.8 breakOut
-
[解決済み】Scalaのyieldとは何ですか?
-
[解決済み】Scala 2.8における<:<、<%<、=:=の意味と、それらのドキュメントはどこにあるのか?
-
[解決済み] Scala:1ステートメントで文字列をファイルに書き込む
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] ScalaのSeqへのアペンド
-
[解決済み] Scalaで定数メンバを定義するには?
-
[解決済み] Scala マップ foreach
-
[解決済み] 理解する `andThen`
-
[解決済み] Spark - CSVファイルをDataFrameとして読み込む?
-
[解決済み】コマンドラインパラメータを解析する最良の方法?[クローズド]
-
[解決済み】case objectとobjectの違いについて
-
[解決済み】Scalaでリスト内のアイテムを取得する?
-
[解決済み】Scalaで`:_*`(コロン・アンダースコア・スター)は何をするのですか?
-
[解決済み] データセットにカスタムオブジェクトを格納する方法は?