Main Content

関数 eval の代替方法

関数 eval の使用が好ましくない理由

eval は非常に強力で柔軟な関数ですが、プログラミング問題において常に最適な解決方法であるとは限りません。eval を呼び出すコードは、他の関数や言語要素を使用するコードに比べて効率が低く、読み取りやデバッグが難しいことがあります。以下に例を示します。

  • MATLAB® では、後の実行パフォーマンスを向上させるため、初回実行時にコードをコンパイルします。しかし eval ステートメント内にあるコードは、実行時に変更される可能性があるためにコンパイルされません。

  • eval ステートメント内のコードによって、現在のワークスペースに既に存在する変数が作成されたり、こうした変数に値が代入されるなどの予期しない動作が発生し、既存のデータが上書きされる可能性もあります。

  • eval ステートメント内の文字ベクトルを連結すると、コードが読みづらくなることがあります。他の言語要素を使用してコードの構文を簡易化できます。

eval の一般的用法の多くは、以下の例に示される手法で代替することが推奨されます。

連番が含まれる名前をもつ変数

関数 eval は、A1A2...An といった一連の変数を作成するためによく使用されますが、この方法では MATLAB の配列処理機能が活かされず、これを推奨することはできません。望ましい方法は、関連するデータを 1 つの配列に格納することです。データセットに含まれるデータの型やサイズが一定でない場合は、構造体または cell 配列を使用します。

たとえば、10 個の要素を含み、その各要素が数値配列である cell 配列を作成します。

numArrays = 10;
A = cell(numArrays,1);
for n = 1:numArrays
    A{n} = magic(n);
end

この cell 配列内のデータにアクセスするには、中かっこのインデックスを使用します。たとえば、A の 5 番目の要素を表示するには、次のようにします。

A{5}
ans =
    17    24     1     8    15
    23     5     7    14    16
     4     6    13    20    22
    10    12    19    21     3
    11    18    25     2     9

代入ステートメント A{n} = magic(n) を使用する方が、次の eval 呼び出しよりも効率がよく、洗練されています。

eval(['A', int2str(n),' = magic(n)'])     % Not recommended

詳細については、以下を参照してください。

連番が含まれる名前をもつファイル

関連するデータ ファイルの名前は、たとえば myfile1.matmyfileN.mat などのように、共通のルート名と整数インデックスで構成される場合がよくあります。関数 eval の一般的な用法として、次のようなコマンド構文を使用して各ファイル名を構成し、関数に渡すことがありますが、これは推奨できません。

eval(['save myfile',int2str(n),'.mat'])     % Not recommended

変数を入力として渡せる関数構文の使用をお勧めします。以下に例を示します。

currentFile = 'myfile1.mat';
save(currentFile)

関数 sprintf を使用してループ内でファイル名を作成し (これは通常 int2str よりも効率的です)、その後 eval を使わずに関数 save を呼び出すことができます。次のコードでは、現在のフォルダーに 10 個のファイルが作成されます。

numFiles = 10;
for n = 1:numFiles
   randomData = rand(n);
   currentFile = sprintf('myfile%d.mat',n);
   save(currentFile,'randomData')
end

詳細については、以下を参照してください。

変数に含まれる関数名

eval は、関数の名前が変数文字ベクトルに含まれる場合、その関数を実行するためによく使用されます。変数から関数を評価するには、eval を使用するよりも効率的な方法が 2 つあります。

  • @ 記号または関数 str2func を使用して関数ハンドルを作成します。たとえば、cell 配列に格納されたリストから関数を実行します。

    examples = {@odedemo,@sunspots,@fitdemo};
    n = input('Select an example (1, 2, or 3): ');
    examples{n}()
  • 関数 feval を使用します。たとえば、実行時に指定されるデータを使ってプロット関数 (plotbarpie など) を呼び出します。

    plotFunction = input('Specify a plotting function: ','s');
    data = input('Enter data to plot: ');
    feval(plotFunction,data)

変数に含まれるフィールド名

可変のフィールド名をもつ構造体のデータにアクセスするには、フィールドの式を小かっこで囲みます。以下に例を示します。

myData.height = [67, 72, 58];
myData.weight = [140, 205, 90];

fieldName = input('Select data (height or weight): ','s');
dataToUse = myData.(fieldName);

入力プロンプトで weight と入力した場合、次のコマンドで weight の最小値を取得できます。

min(dataToUse)
ans =
    90

その他の例は、変数からフィールド名を生成 を参照してください。

エラー処理

MATLAB でエラー処理を行うには、try, catch ステートメントの使用が推奨されます。以下に例を示します。

try
   B = A;
catch exception
   disp('A is undefined')
end

ワークスペースに変数 A がない場合、このコードでは次が返されます。

A is undefined

関数 eval に関するドキュメンテーションの以前のバージョンには eval(expression,catch_expr) 構文が含まれています。expression の入力を評価してエラーが返された場合は、eval によって catch_expr が評価されます。ただし、eval ステートメントで暗黙的にキャッチするよりも、明示的な try/catch を使用する方がはるかに明確です。暗黙的なキャッチの使用は推奨できません。