タプル
タプルは、単一のオブジェクトとして使用する複数の値を組み合わせるためのものだ。これらは、std.typeconsモジュールにあるTupleテンプレートによってライブラリ機能として実装されている。
Tuple一部の操作では、std.metaモジュールにあるAliasSeqを使用している。
この章では、タプルのより一般的な操作のみを説明する。タプルとテンプレートに関する詳細情報は、Philippe Sigaudの「D Templates: A Tutorial」を参照。
Tupleおよびtuple()
タプルは通常、便利な関数tuple()によって構築される。
上記のtupleの呼び出しは、intの値42とstringの値"hello"で構成されるオブジェクトを構築する。プログラムの出力には、タプルオブジェクトとそのメンバーの型が含まれている。
Tuple!(int, string)(42, "hello")
上記のタプル型は、以下の擬似struct定義と同等であり、おそらくまったく同じ方法で実装されている。
タプルのメンバーは通常、そのインデックス値によってアクセスされる。この構文は、タプルがさまざまな型の要素で構成される配列と見なせることを示唆している。
出力:
42
hello
メンバープロパティ
tupleおよびTupleテンプレートがメンバー名でインスタンス化されている場合、プロパティによってメンバーにアクセスすることができる。以下の2つのメソッドは、同じ効果を持つ。
上記の定義により、.numberおよび.messageプロパティからもメンバーにアクセスできる。
出力:
| インデックス0 | 42 |
|---|---|
| .number | 42 |
| インデックス1 | hello |
| .message | hello |
メンバーを値のリストとして展開
タプルメンバーは、関数呼び出し時の引数リストなどとして使用できる値のリストとして展開することができる。メンバーは、.expandプロパティまたはスライスによって展開することができる。
上記のタプルは、int、string、double、charの4つの値で構成されている。これらの型は、foo()のパラメータリストと一致するため、そのメンバーの展開をfoo()の引数として使用することができる。bar()を呼び出すと、タプルの最初のメンバーと最後の2つのメンバーから、一致する引数リストが作成される。
メンバーが同じ配列の要素として互換性がある限り、タプルの展開は配列リテラルの要素値としても使用できる。
上記の配列リテラルは、同じタプルを2回展開して初期化されている:
[1, 2, 3, 1, 2, 3]
コンパイル時foreach
値を展開できるため、タプルはforeach文でも使用できる。
出力:
| 0 | 42 |
| 1 | hello |
| 2 | 1.5 |
上記のforeach文は、実行時にループが実行されるような誤解を与えるかもしれない。しかし、そうではない。むしろ、タプルのメンバーに対して操作を行うforeach文は、各メンバーについてループ本体を展開するものだ。上記のforeach文は、次のコードと同等だ。
展開が行われる理由は、タプルのメンバーが異なる型の場合、foreach体は型ごとに別々にコンパイルされなければならないためだ。
より強力なループ展開機能であるstatic foreachについては、後の章で説明する。
関数から複数の値を返す
タプルは、関数が1つの値しか返せないという制限の簡単な解決策となる。その例がstd.algorithm.findSplitだ。findSplit()は、別の範囲内の範囲を検索し、見つかった範囲の前、見つかった範囲、見つかった範囲の後の3つの部分で構成される結果を生成する。
出力:
| 前 | he |
|---|---|
| 発見 | ll |
| 後 | o |
関数から複数の値を返すもう1つの方法は、structオブジェクトを返すことだ。
AliasSeq
AliasSeqは、std.metaモジュールで定義されている。これは、通常はコンパイラによって使用されるが、それ以外ではプログラマがエンティティとして利用できない概念を表すために使用される。値、型、およびシンボル(つまり、aliasテンプレート引数)をコンマで区切ったリストだ。以下は、そのようなリストの3つの例だ。
- 関数引数リスト
- テンプレート引数リスト
- 配列リテラル要素リスト
次の3行のコードは、同じ順序でこれらのリストを示した例だ。
Tupleメンバーを展開する際、AliasSeqを利用している。
AliasSeqという名前は"alias sequence"から来ており、型、値、およびシンボルを含むことができる。(AliasSeqおよびstd.metaは、以前はそれぞれTypeTupleおよびstd.typetupleと呼ばれていた。)
この章では、型のみ、または値のみで構成されるAliasSeqの例を紹介する。型と値の両方を使用した例については、次の章で説明する。AliasSeqは、可変長のテンプレートで特に有用だ。これについても、次の章で説明する。
AliasSeq値で構成される
AliasSeqが表す値は、そのテンプレート引数として指定する。
3つのパラメータを取る関数を考えてみよう。
この関数は通常、3つの引数で呼び出される。
AliasSeqは、これらの引数を1つのエンティティとして結合し、関数を呼び出すときに自動的に展開することができる。
この関数は1つの引数で呼び出されているように見えるが、上記のfoo()の呼び出しは、前の呼び出しと同等だ。その結果、どちらの呼び出しも、同じ出力が生成される。
| 1 | hello | 2.5 |
また、argumentsは、autoなど、変数として定義されていないことにも注意。これは、特定のAliasSeqインスタンスのaliasだ。AliasSeqの変数を定義することも可能だが、この章の例では、それらをエイリアスとしてのみ使用する。
Tupleで見たように、値が同じ配列の要素として互換性がある場合、AliasSeqを使用して配列リテラルを初期化することもできる。
インデックス付けとスライシング
Tupleと同じように、AliasSeqの要素はインデックスとスライスでアクセスできる:
上記のAliasSeqの最後の2つのメンバーと一致するパラメータを持つ関数があるとする。この関数は、AliasSeqの最後の2つのメンバーだけのスライスを使用して呼び出すことができる。
AliasSeqで構成される
AliasSeqのメンバーは、型で構成することができる。つまり、特定の型の特定の値ではなく、int自体のような型だ。型で構成されるAliasSeqは、テンプレート引数を表すことができる。
2つのパラメータを持つstructテンプレートを持つAliasSeqを使ってみよう。このテンプレートの最初のパラメータはメンバー配列の要素型を決定し、2番目のパラメータはメンバー関数の戻り値を決定する。
上記のコードでは、テンプレートが(double, int)でインスタンス化されていることがわかる。AliasSeqも同じ引数リストを表すことができる:
Typesは単一のテンプレート引数のように見えるが、自動的に展開され、テンプレートのインスタンス化は以前のようにS!(double, int)になる。
AliasSeqは、可変長のテンプレートで特に便利だ。この例については、次の章で説明する。
AliasSeqを使用したforeach
Tupleと同じで、AliasSeqで動作するforeach文は、実行時のループではない。むしろ、各メンバーに対してループ本体が展開される。
これを、上で定義した構造体Sに対して書いたユニットテストで例を見てみよう。次のコードは、要素型int、long、およびfloatについてSをテストする。この例では、ResultTは常にsize_tだ。
foreach変数Typeは、int、long、floatの順に対応している。その結果、foreach文は、以下のコードと同等のコードとしてコンパイルされる。
.tupleofプロパティ
.tupleofは、型またはオブジェクトのメンバーを表する。ユーザー定義型に適用すると、.tupleofはその型のメンバー定義へのアクセスを提供する。
S.tupleofは、プログラム内の2箇所に現れる。まず、要素の型は、typeofを.tupleofに適用して、各型がMemberType変数として現れるように取得される。次に、メンバーの名前は、S.tupleof[i].stringofによって取得される。
| メンバー | 型 | 名前 |
|---|---|---|
| 0 | int | number |
| 1 | string | message |
| 2 | double | value |
.tupleofは、オブジェクトにも適用できる。その場合、オブジェクトのメンバーの値で構成されるタプルが生成される。
foreach変数memberは、オブジェクトの各メンバーを表す:
| メンバー | 型 | 値 |
|---|---|---|
| 0 | int | 42 |
| 1 | string | hello |
| 2 | double | 1.5 |
ここで重要な点は、.tupleofが返すタプルは、オブジェクトのコピーではなく、オブジェクト自体のメンバーで構成されていることだ。つまり、タプルのメンバーは、実際のオブジェクトのメンバーへの参照だ。
要約
tuple()は、structオブジェクトと同様に、異なる型の値を結合する。- メンバーは、プロパティによってアクセスできる。
- メンバーは、
.expandまたはスライスによって値リストとして展開できる。 foreachタプルとの組み合わせは実行時ループではなく、ループの展開だ。AliasSeq関数引数リスト、テンプレート引数リスト、配列リテラル要素リストなどの概念を表す。AliasSeq値と型で構成することができる。- タプルはインデックス付けとスライシングをサポートしている。
.tupleofは、型およびオブジェクトのメンバーに関する情報を提供する。