このコースでは Pharo のコレクションの階層の
要点について学びます。
Pharo には沢山の種類のコレクションが あることがわかるでしょう。
プログラマを楽にしてくれます。
同じ API を共有しているので。
また、リテラルなコレクションと動的なものの 違いについても見てみます。
コレクションには多くの種類があるので その API は多種多様ですが
よく整理された共通 API を共有しているので
プログラマを楽にしてくれます。
Pharo 特有なことは
最初の要素のインデックスが 1 だと いうことです。
0 になっている他の言語と違って。
Pharo では、コレクションは どんな種類のオブジェクトも格納できます。
他の言語では必ずしもそうではありません。
最も素晴らしく、また、広く使われている コレクションをいくつか見てみましょう。
OrderedCollection は 動的なコレクションで
要素を追加するごとに大きくなっていきます。
Array は固定長のコレクションです。
インデックスを使って要素にアクセスできます。
Set は要素を重複なく格納します。
同じ要素を2度追加することはできません。
Dictionary はハッシュテーブルです。 1つのキーに対して1つの値が関連付けられています。
これはコレクションの階層からの抜粋です。
抜粋にすぎません。 Pharo にあるものはもっと大きいです。
沢山のクラスがあります。 どのコレクションも全コレクション共通の
API を持っています。
このコースでは それらの API を太字で示します。
7つの共通 API があります。
クラスに送られる コレクション(creation)生成メソッド
コレクションの特性にアクセスする (accessing)メソッド
（コレクションのサイズや
格納されている要素など）
コレクションを検査する(testing)メソッド （コレクションは空か？）
要素を追加(adding)したり取り除く(removing) メソッドや列挙する(enumerating)メソッド
（要素の一覧を見たり ある要素が格納されているかを見たり）
そしてコレクションを別の種類のものへ 変換する(converting)メソッド
例題から始めて見ましょう。 Pharo でコレクションを作りたいとします。
単に、興味のあるクラスを選んで
new メッセージを送ることで そのクラスのインスタンスを生成します。
1つめの選択肢では new を使います。
2つめの選択肢では、直接 new は使いません。
コレクションの大きさを指定したいとします。
new: 4 を送ることができます。 大きさが 4 や 2 の配列を作ります。
このやり方は OrderedCollection でも使えます。 大きさ 1000 のものを作ることができます。
初期化済みのコレクションを作るメソッドもあります。
例えば withAll: です。
リテラルのコレクションを渡します。 リテラルのコレクションは #( で始まります。
要素を渡して、それが全て格納されているような
OrderedCollection の新しいインスタンスを作ります。
Set でも同じことができます。
Set では重複した要素を持つことはできません。
リテラルのコレクションでは 7 が 2 回現れますが
Set の中では 2 つ持つことはできません。
他にも初期化のために
クラスに送ることができるメッセージが いくつかあります。
new:withAll: もその例です。
大きさが 5 で
全ての要素が特定のオブジェクトであるような コレクションが欲しい、ということです。
この場合、文字列 a です。
Pharo では全てのコレクションで インデックスが 1 から始まることを覚えておいてください。
この 3 要素からなるコレクションに
インデックス 2 の要素を返してもらうと これが返ってきます。
これは 1、これは 2、これは 3 です。
OrderedCollection でも同じです。
このコレクションを変換して インデックス 2 を返してもらうと
hates が得られます。
コレクションにはあらゆる種類のオブジェクトを 格納することができます。
その例をお見せしましょう。
このリテラルのコレクションは 文字列 calvin と
数 1 と 2 と 3 を格納したコレクション を格納しています。
配列を作ることができます。
この配列は要素 1 2 と、そして
集合 (Set) から成っています。
要素 1 をここで そして要素 2、そして集合を追加しました。
例えば do: メッセージを使って
コレクションの要素の一覧を見ることができます。
このコレクションに
do: メッセージを送って ブロックを渡します。
ブロックは [ で始まって ] で終わります。
ブロックの引数は :each です。
引数はブロックの本体から | で区切られています。
ループの各回で、each の値は ブロックの要素を 1 つ目
そして 2 つ目、等となっていきます。
そしてトランスクリプトに Calvin hates Suzie と表示されます。
配列は固定長のコレクションです。
配列に size メッセージを送ることで 大きさを問い合わせることができます。
at: メッセージを送ることで 配列の要素に直接アクセスできます。
2 つ目の要素が欲しいと。
コレクションの要素を変更することができます
at: 1 put: 'Calvin' を送ることで
1番目のセルに文字列 Calvin を入れます。
大きさを尋ねることもできます。
この例で興味深いことは
同じ配列が 2 通りの方法で 作られていることです。
最初のはリテラルのバージョンで そして動的なバージョンです。
ここで、自分でArray クラスから インスタンスを生成して
全てのセルを埋めます。
コレクションに size を送ることで その大きさを知ることができます。
コレクションの要素に at: メソッドを使って アクセスすることができます。
これはもう言いましたね。
注意してください。
インデックスを示して 要素にアクセスする時には
必ずインデックスがコレクションの境界内に あることを確認しなければなりません。
インデックスはコレクションの大きさよりも 小さくなければなりません。
もしコレクションに、 存在しないインデックス 55 の要素を
返すように言ったら エラーが返ってきます。
このコレクションのインデックス 2 に
新しい要素を入れたいとします。
文字列 love が 文字列 hates の代わりに入ります。
結果を見ればおわかりでしょう。
リテラルの配列です。
これはリテラルの配列の例です。
前に言った通り、#( で始まります。
中にはなんでも入ります。 数や文字列などなど
Pharo ではリテラルの配列は
デフォルトで Array クラスのインスタンスです。
リテラル配列に class メッセージを送ると
Array が返ってきます。 Array クラスのインスタンスということです。
動的な配列とリテラル配列は Pharo では同じものです。
リテラル配列は単純に短くかけます。 より速く書くことができます。
ここにはリテラルの配列があります。
そして Array クラスのインスタンスを生成した 動的なバージョンがあります。
それらは同じ結果が得られるので 等しいものです。
OrderedCollectionクラスは 拡大することができる
コレクションを定義します。
要素を追加すると、大きくなります。
new メッセージを送ることで OrderedCollection を生成します。
add: メソッドを使って このコレクションに新しい要素を加えます。
addFirst: を使ってコレクションの 先頭に要素を追加することもできます。
デフォルトでは末尾に追加されます。
コレクションが何を返すかを見てください。
3つの要素から成っています。 Pharo、 Reef、そして Pharo です。
add: 'Seaside'で 末尾に 'Seaside' が追加されます。
変換 (conversion) メソッドで 異なる種類のコレクションに変換することができます。
ここでリテラルのコレクションがあります。 配列です。
asOrderedCollection メッセージは この配列を
OrderedCollection に変換します。
Set は重複のないコレクションです。
Set は拡大することができます。 要素を追加するたびに大きくなります。
リテラルのコレクションを使って そこから Set に変換できます。
重複のない Set が最終的に得られます。
リテラルではなく動的なやり方を 選択することもできます。
Set with: with: は集合を作って 2つの要素を入れます。
それぞれの要素が集合になっています。
変換メソッドは、ある種類のコレクションを 別の種類に変換するのに便利です。
as に欲しいコレクションの名前を付けたものです。
Dictionaryはキーと値のコレクションです。
キーと値を関連付けます。
Dictionary は拡大することができます。 要素を追加するごとに大きくなります。
Dictionaryについては
他のコレクションにないような API があります。
よくある at: メッセージに加えて at:ifAbsent: メッセージ
(アクセスしたいキーが存在していなかった時に どうするか？です）
at:put: はキーに新しい値を入れます。
列挙する時によく使う do: メッセージも 使うことができますが
他のメッセージも使えます。
keysDo: はその辞書の全てのキーを一覧します。
keys や values もあります。
例えば、Dictuionary クラスの インスタンスを生成します。
辞書を配列のように思い描いてみてください。
January をキーとして、31 を関連付けて Februaryをキーとして28
Marchをキーとして31と。
これは動的なコレクションと等価です。
{ と } を使って動的なコレクションを
作ることができます。
関連を作るためには 矢印を使います。
これはシンボルです。
シンボル January に数 31 を関連付けます。
関連のコレクションがあります。
これを asDictionary で Dictionaryに変換します。
辞書を生成するこれら2つの方法は等価です。
関連付けにキーを問い合わせれば
そのキーが返ってきます。 最初のほうです。
同じです。
関連付けに値を問い合わせれば その値を返します。
これがペアであり関連付けです。
辞書について。
辞書の特定の値にアクセスしたい場合には
at: を使って、値を知りたいキーを指定します。
もしキーが存在しなければ
代わりにエラーが得られます。
それを避けるためには at:ifAbsent: を使うことができます。
at: に続いて辞書中にないキーを書きます。
なければ、この値、0 を返します。
このキーはこの辞書に入っていないので 0 が返ってきます。
辞書の中を列挙することができます。 do: を使うと
辞書の値のみを得ることになります。 キーは得られません。
なぜか疑問に思うかもしれません。 とても奇妙です。
しかし実際にはとても合理的です。
もし Dictionary での do: の実装を見れば
何があるかというと ^ self valuesDo: です。
デフォルトでは、辞書に do: を適用すると
キーではなく値だけを一覧します。
もし両方とも一覧したければ
それ用のメソッド keysAndValuesDo: を 使わなければなりません。
keysAndValuesDo: は :k と :y の 2 つの引数をとるブロックを取ります。
:k はキーで v: は値です。
この辞書には中身が詰まっています。
このコースでは
Pharo には沢山の種類のコレクションが 利用できることを学びました。
コレクションには共通の語彙があります。
生成すること
要素にアクセスすること サイズなど
プログラマーを楽にしてくれます。
コレクションを他の種類に 簡単に変換することができます。
他にも、もっと学びました。
何かわからないことがあったら システムの中を見ることはとても簡単です。
Pharo の中身、クラスのコードを読んで コレクションの他のクラスを学ぶことができます。