この例では設定パーサをコンパイル時に生成します。
プログラムが2つの設定項目を持ち、それを下記のstruct
にまとめるとしましょう:
struct Config
{
int runs, port;
string name;
}
この構造体に対するパーサーを書くのは難しいことではないですが、
Config
オブジェクトが変更されるたびにパーサーを更新しなければならないでしょう。
なので、任意の設定項目を読み込めるジェネリックなparse
関数を書いてみたいです。
簡単のためにparse
はkey1=value1,key2=value2
という非常に単純な書式の設定項目を受け付けることにしますが、
同様の手法が任意の設定フォーマットに利用できます。
もちろん多くの有名な設定フォーマットのためのリーダがDUBレジストリには存在します。
"name=dlang,port=8080"がユーザの設定文字列だとしましょう。
そして設定項目をコンマで分割し、各設定に対してparse
を呼び出します。
すべての設定項目がパースされた後、設定オブジェクト全体が印字されます。
parse
で素敵な処理が実際に行われる場所ですが、まずは与えられた設定項目(例: "name=dlang")
を"="でキー("name")と値("dlang")に分割します。
switch文はパースしたキーに対して実行されますが、興味深いのはswitch caseが静的に生成されることです。
c.tupleof
はすべてのメンバのリストを(idx, name)
という形式で返します。
コンパイラはc.tupleof
がコンパイル時にわかることを検出し、コンパイル時にforeachループを展開します。
したがって、Conf.tupleof[idx].stringof
は構造体オブジェクトの各メンバを返し、
各メンバに対してcase文を生成します。
同様に、静的ループの中では各メンバにc.tupleof[idx]
のようにインデックスでアクセスできます。
なので、個々のメンバに設定文字列からパースした値を代入できます。
さらに、分割されたレンジはキーを指しているためdropOne
が必要で、
dropOne.front
は2番めの要素を返します。
さらに、to!(typeof(field))
は入力文字列の設定構造体のメンバの個々の型へのパースを行います。
最後に、foreachループはコンパイル時に展開されbreak
がループを停止します。
しかし、設定項目がパースされた後にはswitch文の次のケースにジャンプしたくないため、
ラベル付されたbreakはswitch文の外に脱出するために使われます。