mcpField
M
matlab-validate-function-arguments

matlab-validate-function-arguments

github.com/matlab開発1.2k84 回インストール1 日前に更新
リポジトリ

matlab-validate-function-arguments について

MATLAB の引数検証を実装・レビューするコーディングエージェント向けのスキルです。`arguments` ブロックの意味や組み合わせ規則、従来の検証方法からの移行と注意点を説明します。

主な機能

  1. 01`arguments` ブロックのサイズ・クラスの意味
  2. 02繰り返し引数と出力引数の規則
  3. 03名前と値の引数およびプロパティの取り込み
  4. 04`inputParser` などからの移行
  5. 05暗黙変換に関する注意点

活用シーン

  1. 01MATLAB 関数に引数検証を追加
  2. 02関数シグネチャの型とサイズの挙動を確認
  3. 03`inputParser` の検証を `arguments` ブロックに移行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-validate-function-arguments

インストール後、Claude Code で/matlab-validate-function-argumentsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

manifest.yaml
references/
migration-guide.md
validators-reference.md
references/examples/
dot-question-syntax.md
repeating-args.md

詳細

MATLAB 関数の引数検証

arguments ブロックを使い、サイズ、クラス、反復引数、プロパティのインポートに関する正しいセマンティクスで、堅牢な MATLAB 関数を作成します。

使用する場面

  • arguments ブロックを含む関数を作成する場合
  • 反復引数(arguments (Repeating))を使用する場合
  • 名前と値の引数を受け取るクラスコンストラクターを作成する場合
  • inputParser または validateattributes から移行する場合
  • 暗黙的な変換の落とし穴がないか、関数シグネチャを確認する場合
  • クラス指定、mustBeA、バリデーターのいずれを使うか選ぶ場合

使用しない場面

  • 引数検証を伴わない基本的な MATLAB プログラミング
  • アプリの構築や UI コンポーネント(matlab-build-app を使用してください)
  • 単体テスト(matlab-write-tests を使用してください)
  • 引数検証に関係しない一般的な OOP クラス設計
  • 関数本体内の実行時の不変条件に対する単純な if/error ガード節 (これらは入力検証ではありません。ユーザーが特に arguments ブロックを求めない限り、そのままにしてください)
  • .mlx(Live Script)または .mlapp(App Designer)ファイル — これらはバイナリの ZIP コンテナーです。解凍したり、構造を編集したりしないでください。ユーザーがその中の関数に arguments ブロックを追加するよう求めた場合は、まず通常の .m ファイルとしてエクスポートするか、 MATLAB でファイルを開いて編集するよう依頼してください。

重要な誤解

エージェントがよく間違える点です。最初に確認してください。

サイズ指定は拒否ではなく、形状を変更します

誤った認識: (1,:) は列ベクトルをエラーで拒否します。

実際の動作: MATLAB は入力を、宣言されたサイズに合うよう暗黙的に形状変更します。

function out = myFunc(x)
    arguments
        x (1,:) double
    end
    out = x;
end

myFunc([1; 2; 3])  % Does NOT error! Returns [1 2 3] (reshaped to row)

(1,:) に渡された列ベクトル [1;2;3] は、行ベクトル [1 2 3] になります。列ベクトルを実際に拒否するには、バリデーターを使用してください。

function out = myFunc(x)
    arguments
        x {mustBeNumeric, mustBeRow}
    end
    out = x;
end
クラス指定は拒否ではなく、変換します

誤った認識: arguments ブロック内の double は、double 以外の入力を拒否します。

実際の動作: MATLAB は、入力を宣言されたクラスに暗黙的に変換しようとします。

function out = myFunc(x)
    arguments
        x double
    end
    out = x;
end

myFunc('hello')  % Does NOT error! Returns [104 101 108 108 111] (ASCII codes)
myFunc(single(3.14))  % Does NOT error! Returns double(3.14)

変換せずに拒否するには、mustBeA または mustBeFloat を使用してください。

x {mustBeA(x, "double")}           % Rejects single, char, int32, etc.
x {mustBeFloat}                     % Accepts single OR double, rejects char/int
x {mustBeNumeric}                   % Accepts any numeric, rejects char/string
数値バリデーターは複素数を拒否しません

誤った認識: mustBeNumeric、mustBeFinite、mustBeInteger は、 1+2i のような複素数の入力を拒否します。

実際の動作: 複素数は数値であり、有限であり(実部と虚部が整数値の場合は)整数でもあるため、 1+2i はこれら3つすべてを何も通知せずに通過します。サイズ、インデックス、個数、そしてほとんどの 物理量のスカラー値では、複素数を明示的に拒否する必要があります。

function H = hilb2(n)
    arguments
        n (1,1) {mustBeInteger, mustBePositive, mustBeReal}
    end
    H = 1./((1:n)' + (0:n-1));
end

関数の契約上、複素数の入力が不適切な場合は、必ず mustBeReal を追加してください。

計算されるデフォルト値が参照するのは、宣言されたデフォルト値ではなく渡された値です

誤った認識: デフォルト式は、先行する引数に宣言されたデフォルト値を使って評価されます。

実際の動作: デフォルト式は、実際に渡された値を使って評価されます。

function out = myFunc(fs, windowSize)
    arguments
        fs (1,1) double {mustBePositive}
        windowSize (1,1) double {mustBePositive} = round(fs / 10)
    end
    out = windowSize;
end

myFunc(8000)      % windowSize = round(8000/10) = 800 (uses passed fs)
myFunc(8000, 256) % windowSize = 256 (explicitly passed)

これにより、センチネル値([])や検証後の修正処理が不要になります。

~ は有効なプレースホルダーです。名前を変更しないでください

誤った認識: arguments ブロック内では名前が必須なので、関数シグネチャ内の ~ プレースホルダーは obj/this などに変更しなければなりません。

実際の動作: ~ は引数ブロック内の名前として有効です(R2019b 以降)。そのままにしてください。

function normalize(~, results)
    arguments
        ~
        results (1,:) struct
    end
    ...
end

メソッドシグネチャで未使用の入力(未使用のクラスインスタンスなど)を示すために ~ を使っている場合は、 arguments ブロック内でも ~ を維持してください。

  • ~ にクラス指定やサイズ指定を付けないでください — (1,1) MetricCalculator のような型指定には名前が必要なため、指定を追加すると名前の変更を強いられます。指定自体を省略してください。
  • %#ok<INUSL>/%#ok<INUSA>/%#ok<MANU> のプラグマは付けないでください — ~ によって、入力が意図的に未使用であることはすでにリンターに伝わります。
  • 「検証を強化する」ために ~ を obj に変更しないでください。名前を変更すると、契約上の利点がないまま、元の ~ が抑制していたリンターの警告が再び発生します。

パターン

繰り返し引数

arguments (Repeating) は、引数のグループを可変数受け取る関数(plot(x1,y1,x2,y2,...) など)で使用します。宣言した各変数は、関数本体内でセル配列になります。

function plotMultiSeries(x, y)
    arguments (Repeating)
        x (1,:) double {mustBeFinite}
        y (1,:) double {mustBeFinite}
    end

    figure;
    hold on;
    for i = 1:numel(x)
        plot(x{i}, y{i});
    end
    hold off;
end

主なルール:

  • 変数はセル配列になります。x(i) ではなく x{i} でアクセスします
  • グループ内のすべての変数は、ひとまとまりの完全なセットとして一緒に繰り返されます
  • 繰り返し引数には既定値を設定できません
  • 繰り返しがゼロ回でも有効です(空のセル配列が生成されます)
出力引数の検証 — arguments (Output) と (Output, Repeating)

R2022b 以降。 出力引数の検証は、それ以前のリリースでは使用できません。 入力検証(このスキルの大部分)は R2019b 以降で機能します。

arguments (Output, Repeating) を使用して、出力数が nargout に応じて変化する関数を宣言します。このブロックで宣言する名前は正確に 1 つでなければなりません。複数の名前を持つ繰り返し出力ブロックは MATLAB によって拒否され、MATLAB:functionValidation:MultipleRepeatingOutputs が発生します。関連する値のグループ(たとえば 3 つ組)を返すには、単一の出力にまとめ、呼び出し側で N * groupSize 個の出力を要求します。

function out = productTriples()
    arguments (Output, Repeating)
        out (1,1) double
    end
    out = cell(1, nargout);
    for k = 1:3:nargout
        b = rand;
        c = rand;
        out{k}   = b * c;
        out{k+1} = b;
        out{k+2} = c;
    end
end

呼び出し側:[p1, a1, b1, p2, a2, b2] = productTriples();

主なルール:

  • 名前は 1 つだけです。arguments (Output, Repeating) a; b; c; end は解析時にエラーになります
  • 出力には 1×nargout のセル配列が割り当てられます。呼び出し箇所でのカンマ区切りリストの展開によって、その内容が要求された LHS 変数に分配されます
  • 宣言された唯一の名前に付けたバリデーターは、各セル要素に適用されます
  • nargout で要求された出力数を関数本体に伝えます。ゼロも有効です
構成ルール — 共存可能なもの

関数には複数の arguments ブロックを指定できます。以下のルールは関数全体に適用されます。引数のカテゴリは、すべてのブロックを通じて次の順序で指定する必要があります。

required → optional (with defaults) → repeating → name-value

別々のブロック間であっても、順序に違反すると解析に失敗します。直感に頼らないでください。次のすべての組み合わせは、1 つの関数内で合法的に構成できます。

  • 必須 + オプション + 繰り返し + 名前と値(.?ClassName も使用可能)
  • 必須 + 繰り返し + 名前と値
  • 繰り返し + 名前と値
  • (Output, Repeating) と、入力ブロックの任意の組み合わせ
  • (Repeating) ブロック内の ~ プレースホルダー

多重度:

ブロックの種類許可される数
通常の arguments(位置引数および/または名前と値の引数)複数、順序どおり
arguments (Repeating)(入力)関数ごとに正確に 1 つ
arguments (Output, Repeating)関数ごとに正確に 1 つ
通常のブロックをまたぐ名前と値の構造体複数可 — 構造体名が異なる場合

解析時のエラー識別子 — 判断に迷ったら、関数を書いて MATLAB に確認してください。以下は構成によって発生するエラーのみです。識別子からルールが分かります。

識別子意味
MATLAB:functionValidation:RequiredAfterOptional既定値のある引数の後に必須引数が指定されています
MATLAB:functionValidation:OptionalAfterRepeating繰り返しブロックの後にオプション引数または位置引数が指定されています
MATLAB:functionValidation:PositionalAfterNamed名前と値の引数の後に位置引数または繰り返し引数が指定されています
MATLAB:functionValidation:MultipleRepeatingBlocks(Repeating) ブロック(入力または出力)が複数あります
MATLAB:functionValidation:RepeatingHasDefault(Repeating) 引数に既定値が設定されています

組み合わせが合法かどうか分からない場合は、根拠のない制限を作らないでください。最小限のコードを書いて実行してください。エラー識別子の有無が答えです。

最大限の例

必須引数+オプション引数+無視される引数+繰り返し引数+無視される繰り返し引数+名前と値の引数+クラスからインポートされた名前と値の引数(ここでは SensorConfig — 上記の .?ClassName セクションで定義されたクラス)を含む単一の関数です。

function maximal(req, opt, ~, x, ~, options, classArg)
    arguments
        req (1,1) double
        opt (1,1) double = 7
        ~
    end
    arguments (Repeating)
        x (1,1) double
        ~
    end
    arguments
        options.Title (1,1) string = "default"
        options.Verbose (1,1) logical = false
        classArg.?SensorConfig
    end
    % function body
end

呼び出し:maximal(1, 2, 3, 4, 'a', 5, 'b', Title="t", SampleRate=44100) — 解析して実行されます。SampleRate は、.? 行によって SensorConfig からインポートされた名前と値の引数の1つです。

.?ClassName に、パブリックに設定可能なプロパティがないクラスを選ばないでください。たとえば onCleanup には task(プライベート設定)しかないため、.?onCleanup では名前と値の引数が1つもインポートされません。この行は構文的には有効ですが何もしません。また、呼び出し側が指定した「名前と値」の引数は未知の名前として扱われます。Common Mistakes の「未知の Name=Value は黙って無視される」を参照してください。

繰り返し引数と名前と値のオプションの組み合わせについては、上記の最大限の例と references/examples/repeating-args.md を参照してください。

.?ClassName — プロパティを名前と値の引数としてインポートする

コンストラクターで .?ClassName を使用すると、プロパティ定義から名前と値の引数を直接導出できます。これにより、arguments ブロック内でプロパティを再宣言する必要がなくなります。

特定のプロパティのオーバーライド、転送を行う静的ファクトリー、グラフィックスクラスのプロパティのラップなど、その他のパターンについては、references/examples/dot-question-syntax.md を参照してください。

classdef SensorConfig
    properties
        SampleRate (1,1) double {mustBePositive} = 1000
        Resolution (1,1) double {mustBePositive, mustBeInteger} = 16
        FilterOrder (1,1) double {mustBePositive, mustBeInteger} = 4
        Label (1,1) string = "unnamed"
    end

    methods
        function obj = SensorConfig(nvArgs)
            arguments
                nvArgs.?SensorConfig
            end
            props = fieldnames(nvArgs);
            for i = 1:numel(props)
                obj.(props{i}) = nvArgs.(props{i});
            end
        end
    end
end

メリット:

  • サイズ、クラス、バリデーター、デフォルト値の重複がありません
  • プロパティの追加や削除時に、コンストラクターが自動的に同期されます
  • 設定可能なすべてのプロパティが自動的にタブ補完に表示されます
namedargs2cell — 名前と値の引数を転送する

namedargs2cell を使用すると、検証済みの構造体を名前と値のセル配列に変換して、他の関数に転送できます。

function obj = fromPreset(presetName, nvArgs)
    arguments
        presetName (1,1) string
        nvArgs.?SensorConfig
    end

    switch presetName
        case "audio"
            defaults = struct(SampleRate=44100, Resolution=24, Label="audio");
        case "vibration"
            defaults = struct(SampleRate=10000, Resolution=16, Label="vibration");
    end

    % Apply overrides
    overrides = fieldnames(nvArgs);
    for i = 1:numel(overrides)
        defaults.(overrides{i}) = nvArgs.(overrides{i});
    end

    args = namedargs2cell(defaults);
    obj = SensorConfig(args{:});
end

移行判断のフレームワーク

inputParser または validateattributes から移行する際は、クラスの扱いについて次の判断ツリーを使用してください。

元のチェック動作arguments ブロックでの同等の記述理由
@isnumeric変換せず、任意の数値を受け入れる{mustBeNumeric}クラス指定がないため、変換されません
@ischarchar のみを受け入れる{mustBeA(label, 'char')} または (1,:) charmustBeText/mustBeTextScalar は string も受け入れるため、範囲が広がります
@islogicallogical のみを受け入れる(1,1) {mustBeA(x, 'logical')}logical クラス指定は変換を行います。logical(1) → true となるため、@islogical が拒否する 1/0(および変換可能なその他のスカラー)も受け入れられます。変換せずに拒否するには、mustBeA(クラス指定なし)を使用してください。
{'numeric'}変換せず、任意の数値を受け入れる{mustBeNumeric}validateattributes のメタクラスです。@isnumeric と同じ集合を受け入れます
{'float'}single または double を受け入れる{mustBeFloat}{'single','double'} と同等です
{'integer'}(クラス指定、まれ)整数型(int8…uint64)のみを受け入れる通常は {mustBeNumeric, mustBeInteger}。意図的に厳密にする場合のみ:{mustBeA(x, ["int8","int16","int32","int64","uint8","uint16","uint32","uint64"])}クラスのみを指定する形式では、5.0 のような整数値の double が拒否されます。通常、これは意図しない動作です。元のコードが double を明確に拒否する意図でない限り、より寛容な組み合わせにしてください。
{'numeric'}, {'integer'}(クラス+属性)数値で、整数値であることを受け入れる{mustBeNumeric, mustBeInteger}よく使われる組み合わせです。整数型と整数値の浮動小数点数の両方を受け入れます
{'single','double'}浮動小数点型に限定する{mustBeFloat}クラス指定 double は single を double に変換します
{'double'} 完全一致single、int、char を拒否する{mustBeA(x, "double")}クラス指定 double は拒否ではなく変換を行います
@(x) isa(x,'MyClass')クラスへの所属を確認する{mustBeA(x, "MyClass")}変換せずに検証します

重要な原則: 元のコードが型の不一致を拒否する場合は、バリデーター(mustBeA、mustBeFloat、mustBeNumeric)を使用してください。呼び出し側の利便性のために自動変換を行いたい場合は、クラス指定を使用してください。

無名関数バリデーター

移行時にこれらを削除しないでください — それぞれに組み込みの等価物があります:

inputParser バリデーターarguments ブロックの等価物
@(x) ~isempty(x){mustBeNonempty}
@(x) x > 0{mustBePositive}
@(x) x >= 0{mustBeNonnegative}
@(x) x < 0{mustBeNegative}
@(x) x <= 0{mustBeNonpositive}
@(x) isfinite(x){mustBeFinite}
@(x) isreal(x){mustBeReal}
@(x) isnumeric(x) && isreal(x){mustBeNumeric, mustBeReal}
@(x) ismember(x, set){mustBeMember(x, set)}
validatestring(x, set)mustBeMember で置き換えないでください。 validatestring は大文字小文字を区別しない前方一致を行い、正規形を返します。mustBeMember は完全一致のみです。呼び出しは本体の内部に残し、arguments ブロックは {mustBeTextScalar} のみに使用してください。

移行の詳細な例については、references/migration-guide.md を参照してください。

規約

  • 新しいコードでは(移行ではなく)char よりも string を優先する
  • arguments (Repeating) や名前と値のブロックで同じインターフェースを表現できる場合、手動解析を伴う varargin を決して使用しない
  • プロパティを再宣言するのではなく、コンストラクターで .?ClassName を使用する
  • デフォルトが先行する引数のみに依存する場合、isempty チェックを伴うセンチネル値よりも 計算されたデフォルト(= expression)を優先する
  • 非数値入力の拒否に mustBeNumeric と double クラス指定を組み合わせないでください — クラス指定はバリデーターが実行される前に char('A' → 65)を変換してしまい、チェックが無効になります。クラス指定を削除してください: x (1,1) double {mustBeNumeric} ではなく x {mustBeNumeric}
  • テキストバリデーターと string クラス指定を組み合わせないでください — クラス指定はバリデーターが実行される前に非テキスト(例: 42 → "42")を変換してしまい、チェックが無効になります。テキストバリデーターのみを使用してください: p (1,1) string {mustBeTextScalar} ではなく p {mustBeTextScalar}
  • 型を拒否するために varargin + 手動の class() チェックに頼らないでください。 double のようなクラス指定が char/single/int 入力を(拒否するのではなく)変換してしまう場合、正しい答えはバリデーター(mustBeNumeric、mustBeFloat、mustBeA)であり、varargin へのフォールバックではありません。varargin にフォールバックすると、arguments ブロックの意義そのものが台無しになります。

よくある間違い

間違いなぜ間違っているのか正しいアプローチ
繰り返し引数グループに varargin を使用する30 行以上の手動パースが必要になるarguments (Repeating) — 3 行で済む
コンストラクターでプロパティを再宣言する重複が同期からずれていくnvArgs.?ClassName
(1,:) が列を拒否すると考える黙って形状を変更する拒否するには mustBeRow を使用する
double が char を拒否すると考えるバリデーターが実行される前に黙って ASCII に変換するdouble のクラス指定を削除して {mustBeNumeric} のみを使用するか、厳密なクラスチェックには {mustBeA(x,"double")} を使用する
計算されたデフォルト値に [] センチネルを使用する過剰な設計で、カスタムバリデーターが必要になる先行する引数を参照する = expression
@ischar を mustBeTextScalar に置き換えるstring を受け入れるように契約が広がる厳密な忠実性には mustBeA(x,'char') を使用する
(1,1) string {mustBeTextScalar} を使用するクラス指定がバリデーターの前に 42 → "42" に変換する{mustBeTextScalar} のみを使用する(クラス指定なし)
validatestring を mustBeMember に置き換えるvalidatestring は大文字小文字を区別しないプレフィックスマッチング('AU' → 'auto')を行い、正規形を返す。mustBeMember は完全一致のみ本体の中で validatestring を維持する。arguments ブロックは型/サイズのガードにのみ使用する: mode {mustBeTextScalar} の後に mode = validatestring(mode, {...})
数値引数に mustBeReal を省略する複素数値は mustBeNumeric、mustBeFinite、mustBeInteger を黙って通過する — 1+2i は有限の数値整数である複素数の入力が無意味になる場合(インデックス、サイズ、カウント、物理スカラー)は常に mustBeReal を追加する
arguments ブロックで ~ を obj/this に改名する~ は arguments ブロックで有効なプレースホルダー名である — 改名すると元の ~ が抑制していた lint 警告が再び発生する~ を維持し、クラス/サイズ指定も %#ok プラグマも付けない
arguments (Output, Repeating) で複数の名前を宣言するMATLAB が MultipleRepeatingOutputs エラーを出す — 許可される名前は 1 つだけ単一の出力名を宣言する。値のグループをその 1 つのセル配列にまとめ、呼び出し側に N * groupSize 個の出力を要求させる
オプションの位置引数と (Repeating) が相互排他的であると主張するそうではない — 必須 + オプション + 繰り返し + 名前と値はすべて順番に合法に組み合わせられる「組み合わせルール」を参照してください。不明な場合は、関数を書いて MATLAB のパース時エラー識別子(例: OptionalAfterRepeating、PositionalAfterNamed)に実際に何が問題なのかを教えてもらいましょう
関数に arguments (Repeating) があるとき、未知の Name=Value が大きなエラーになると仮定するそうはならない。(Repeating) ブロックが存在する場合、認識されない Name=Value は 2 つの位置繰り返し引数(名前トークン、次に値)として黙って吸収される。1 つの不正なペアはさらに、先行する有効な名前と値の引数を位置引数に再分類するため、設定オプションがデフォルトに戻ってしまう。((Repeating) がない場合、同じ呼び出しは MATLAB:TooManyInputs でエラーになる。)ここに陥るよくある原因: 公開設定可能なプロパティを持たないクラス(例: .?onCleanup)に対して .?ClassName を使用すること — このインポートは何も公開しないため、呼び出し側がそれに対して書くすべての NV が未知となる。公開設定可能なプロパティを持つクラスを選んでください。「なぜ私の NV デフォルトが表示されるのか?」をデバッグするときは、呼び出しに認識されない Name= がないか確認してください — 1 つの不正な名前が NV セクション全体を台無しにします

バリデーター早見表

バリデーター目的備考
mustBeFloat単精度または倍精度のみを受け入れます整数、文字は拒否します
mustBeA(x, classes)変換せずに厳密なクラスチェックを行いますmustBeA(x, ["single","double"])
mustBeBetween(x, lo, hi, type)範囲チェックR2025a 以降。R2025a より前では、mustBeGreaterThan/mustBeLessThan を使用します
mustBeNonNanNaN 値を拒否します組み込み機能であり、カスタムではありません
mustBeMatrix2 次元(M 行 N 列)を必須としますR2024b 以降
mustBeRow1 行 N 列を必須としますR2024b 以降。(1,:) とは異なり、列ベクトルを拒否します
mustBeVector行ベクトルまたは列ベクトルを受け入れます向きを柔軟に指定できます
mustBeSorted要素がソート済みであることを必須としますR2026a 以降

バリデーターの完全なリファレンスについては、references/validators-reference.md を参照してください。


Copyright 2026 The MathWorks, Inc.


コメント