7

D 文字列 mixin に慣れていない方のために説明すると、それらは基本的にコンパイル時の評価です。コンパイル時の任意の文字列 (リテラルまたはテンプレート メタプログラミングまたはコンパイル時の関数評価によって生成されたもの) を取得して、コードとしてコンパイルできます。単純な文字列リテラルを使用する場合、それは基本的にコンパイラによって自動化されたコピー アンド ペーストです。

因数分解の他の方法がうまく適合しない場合に、単純なコードの再利用の手段としてリテラルの文字列ミックスインを使用することはアンチパターンだと思いますか? 一方で、これは基本的にコンパイラによって自動化されたリテラルのコピー アンド ペーストです。文字列 mixin 内のシンボルが mixin スコープ内のシンボルと衝突すると、(実行時ではなくコンパイル時に) 悪いことが起こります。たとえば、スコープ内の変数が特定の規則に従って名前が付けられている場合にのみ機能する関数の途中に文字列を混在させることができるという点で、比較的構造化されていません。ミックスインは、外部スコープが適切と判断した場合に使用できる変数を宣言することもできます。

一方、コピー アンド ペーストはコンパイラで自動化されているため、問題のコードのソース レベルでの唯一の真実のポイントがあり、変更が必要な場合は 1 か所だけ変更する必要があります。すべてが同期します。また、文字列 mixin は、他の方法では因数分解が非常に困難で、手動で切り貼りする可能性が非常に高いコードの再利用を大幅に簡素化します。

4

3 に答える 3

11

あなたが提起したすべての批判は真実です。

とにかく、手動のコピーペーストよりも優れています.

実際、私のツール ライブラリでは、文字列テーブルの拡張という、似たようなものを実行しています。パス トレーサーの動的な値の実装からのコード例:

  T to(T)() {
    static if (!is(T == Scope)) {
      T value;
      if (flatType == FlatType.ScopeValue) value = sr.value().to!(T);
    }
    const string Table = `
                 | bool          | int         | string               | float   | Scope
      -----------+---------------+-------------+----------------------+---------+----------
      Boolean    | b             | b           | b?q{true}p:q{false}p | ø       | ø
      Integer    | i != 0        | i           | Format(i)            | i       | ø
      String     | s == q{true}p | atoi(s)     | s                    | atof(s) | ø
      Float      | ø             | cast(int) f | Format(f)            | f       | ø
      ScopeRef   | !!sr          | ø           | (sr?sr.fqn:q{(null:r)}p) | ø   | sr
      ScopeValue | value         | value       | value                | value   | sr`;
    mixin(ctTableUnrollColMajor(Table,
      `static if (is(T == $COL))
        switch (flatType) {
          $BODY
          default: throw new Exception(Format("Invalid type: ", flatType));
        }
      else `,
      `case FlatType.$ROW:
        static if (q{$CELL}p == "ø")
          throw new Exception(q{Cannot convert $ROW to $COL: }p~to!(string)~q{! }p);
        else return $CELL;
      `
    ).litstring_expand() ~ `static assert(false, "Unsupported type: "~T.stringof); `);
  }

文字列の mixin がなければ、ネストされた if 文と case 文の恐ろしく冗長な混乱がどのようなものかは簡単にわかると思います。このようにして、すべての醜さは下部に集中し、関数の実際の動作は読みやすくなります。一目でオフ。

于 2010-07-21T15:21:48.490 に答える
3

可能であれば、他のよりエレガントなソリューションを使用する方がよい場合もありますが、ストリングミックスインは非常に便利です。これらは、コードの再利用とコード生成の両方を可能にします。それらはコンパイル時にチェックされます。結果として得られるコードは、自分で手書きした場合とまったく同じであるため、自分で手書きした場合と同じくらい安全です。

文字列ミックスインの問題は、エラーまで明確に追跡可能な行番号と同じようにソースに物理的に配置されていないという意味で、手書きのコードよりも制御が難しく、デバッグが難しい場合があることです。たとえば、文字列ミックスインを使用してhelloworldを取得します。

import std.stdio;

void main()
{
    mixin(hello());
}

string hello()
{
    return "
    writeln(\"hello world\");
";
}

の後にセミコロンを削除すると、writeln()取得したエラーは次のようになります。

d.d(7): found 'EOF' when expecting ';' following statement

ミックスインは5行目で行われます。7行目は空白行です。したがって、ここでは行番号の有用性は限られています。さて、このミックスインは十分に短いので、1行に配置して、エラーはミックスインと同じ行にあると言うことができますが、より複雑なミックスインでは、明らかに機能しません。したがって、ストリングミックスインを使用すると、エラーがどこにあるかを把握する能力が損なわれます。コードがCTFEを使用して生成された場合、コードの何が問題になっているのかを把握するために、コードがどのように見えるかを正確に把握することは非常に困難になります。これは、Cスタイルのマクロがどのコードに変わるかを理解するのとよく似ていますが、直接置き換えるのではなく生成される可能性があるため、さらに悪い場合があります。ただし、明示的に指示した場合を除いて、それらは置き換えられないため、

ストリングミックスインは完全に安全であり、特に問題はありませんが、いくつかの点でメンテナンスが難しくなります。対応する手書きのコードは、デバッグが簡単です。ただし、文字列ミックスインは十分に強力であるため、多くのコード生成を実行でき、その意味で多くの保守コストを節約できます。また、コードを再利用できるため、保守の大幅な向上にもなります。

したがって、特定の状況で文字列ミックスインを使用することが適切かどうかは、その状況によって異なります。私はそれらに特に悪いことは何も見ていません、そして私は確かにそれらをアンチパターンとは呼びませんが、それらを使用することには賛否両論があり、それらが良いアイデアであるかどうかはあなたがしていることに依存します。多くの場合、よりエレガントでクリーンなソリューションがあります。他では、それらはまさに医者が注文したものです。

個人的には、コードを生成することを検討している場合、それらは素晴らしいと思います。手作業でそのコードを作成する手間を省き、さまざまな状況で正しいコードを生成しやすくし、新しいコードを作成するリスクを回避できます。ミックスインを使用した場所のそれぞれで自分で書いたかもしれないようなバグ。これは、関数呼び出しのコストや、単一継承の制限など、関数や継承を呼び出すことによってコードを再利用するのを困難にする問題を気にせずに、コードを完全に再利用する方法の1つでもあります。コードを変更した場合に、コードを変更した場合に、コードをコピーして各場所に貼り付けるだけです。

したがって、必要に応じて文字列ミックスインを使用します。不要な場合は使用しないのがおそらく最善ですが、実際に使用しても問題はありません。

于 2010-07-21T17:19:40.663 に答える
1

String mixin は goto のようなものです: 可能な限り避けるべきであり、必要に応じて使用する必要があります。

于 2010-07-22T04:13:27.270 に答える