我可能会花几个小时来解决这个问题,但是对于一般的Matlab签名处理,仍然没有很好的格式塔视图。但是这里有一些建议。
首先,采用自由放任的方法来验证输入类型。相信来电者。如果您确实需要强类型测试,则需要像Java这样的静态语言。尝试在Matlab中的每个地方强制执行类型安全,您将最终获得大部分的LOC和执行时间,专门用于在用户区中进行运行时类型测试和强制执行,这折衷了Matlab的强大功能和开发速度。我经过惨痛的教训才学到这个。
对于API签名(打算从其他函数而不是从命令行调用的函数),请考虑使用单个Args参数而不是varargin。然后,可以在多个参数之间传递它,而不必将其与来回用逗号分隔的varargin签名列表进行转换。就像乔纳斯(Jonas)所说的那样,结构非常方便。在结构和n-by-2 {name,value; ...}单元格之间也有很好的同构,您可以设置几个函数以在函数内部将它们之间转换为内部要使用的任何函数。
function example(args)
无论您使用inputParser还是像其他其他出色示例一样滚动自己的名称/值解析器,都将其打包到一个单独的标准函数中,该函数将从具有名称/值签名的函数顶部调用。让它接受方便写出的数据结构中的默认值列表,并且您的arg解析调用看起来类似于函数签名声明,这有助于提高可读性并避免复制粘贴示例代码。
这就是解析调用的样子。
function out = my_example_function(varargin)
args = parsemyargs(varargin, {
'Stations' {'ORD','SFO','LGA'}
'Reading' 'Min Temp'
'FromDate' '1/1/2000'
'ToDate' today
'Units' 'deg. C'
});
fprintf('\nArgs:\n');
disp(args);
typed_args = parsemyargs(varargin, {
'Stations' {'ORD','SFO','LGA'} 'cellstr'
'Reading' 'Min Temp' []
'FromDate' '1/1/2000' 'datenum'
'ToDate' today 'datenum'
'Units' 'deg. C' []
});
fprintf('\nWith type handling:\n');
disp(typed_args);
这是一个以这种方式实现名称/值解析的函数。您可以将其挖空并将其替换为inputParser,您自己的类型约定等。考虑保留。在接收代码中,结构通常更方便处理,但是使用表达式和文字构造n×2单元更方便。(结构需要在每行连续加上“,...”,并防止单元格值扩展为非标量结构。)
function out = parsemyargs(args, defaults)
args = structify(args);
defaults = parse_defaults(defaults);
out = merge_args(args, defaults);
function out = parse_defaults(x)
if isstruct(x)
if ~isscalar(x)
error('struct defaults must be scalar');
end
x = [fieldnames(s) struct2cell(s)];
end
if ~iscell(x)
error('invalid defaults');
end
if size(x,1) == 1 && size(x,2) > 3
x = reshape(x, [numel(x)/2 2]);
end
if size(x,2) < 2
x(:,2) = {[]};
end
if size(x,2) < 3
x(:,3) = {[]};
end
out = x;
function out = structify(x)
if isempty(x)
out = struct;
elseif iscell(x)
if (size(x,1) == 1) && size(x,2) > 2
x = reshape(x, [2 numel(x)/2]);
end
if size(x,2) ~= 2
error('Invalid args: cells must be n-by-2 {name,val;...} or vector {name,val,...} list');
end
if ~iscellstr(x(:,1))
error('Invalid names in name/val argument list');
end
x(:,2) = num2cell(x(:,2));
x = x';
x = x(:);
out = struct(x{:});
elseif isstruct(x)
if ~isscalar(x)
error('struct args must be scalar');
end
out = x;
end
function out = merge_args(args, defaults)
out = structify(defaults(:,[1 2]));
names = fieldnames(args);
for i = 1:numel(names)
out.(names{i}) = args.(names{i});
end
for i = 1:size(defaults,1)
[name,defaultVal,type] = defaults{i,:};
if ~isempty(type)
out.(name) = needa(type, out.(name), type);
end
end
function out = needa(type, value, name)
switch type
case 'cellstr'
isThatType = iscellstr(value);
case 'datenum'
isThatType = isnumeric(value);
otherwise
isThatType = isa(value, type);
end
if isThatType
out = value;
else
try
out = feval(type, value);
catch err
error('Failed converting argument %s from %s to %s: %s',...
name, class(value), type, err.message);
end
end
不幸的是,在Matlab中,字符串和datenum不是一流的类型。