提问人:magnesium 提问时间:9/19/2023 最后编辑:Luis Mendomagnesium 更新时间:9/20/2023 访问量:128
如果没有请求输出,如何提前退出功能?
How to exit function early if outputs are not requested?
问:
我正在编写一个具有多个输入和输出的函数。只有在极少数情况下才需要所有输出。 此外,一些输入仅用于生成一些不频繁的输出。
一个简化的例子可以说明:
function [out1, out2] = foo(inp1, inp2, inp3)
out1 = inp1 + inp2; % only requires inp1 and inp2
out2 = inp1 + inp2 + inp3; % requires all inputs
end
如果我运行,我会天真地期望这能起作用:因为没有请求,不应该是必需的(我希望程序在第一行之后终止)。但是,这会导致错误并停止代码的进度。a = foo(1, 2);
out2
inp3
我的问题是:规避这个问题的最简单方法是什么?是否有内置功能或已知的设计模式用于缓解此问题?理想情况下,它不需要任何嵌套。类似的示例发生在整个代码中的多个位置,因此理想情况下,该解决方案也可以重复。
可能的解决方案:
检查输入/输出是可行的,但不能重复。例如
function [out1, out2] = foo(inp1, inp2, inp3)
out1 = inp1 + inp2; % only requires inp1 and inp2
if nargout > 1
out2 = inp1 + inp2 + inp3; % requires all inputs
end
end
如果以这种方式测试多个条件,将导致大量嵌套。
使用可能是解决方案的开始,但并不理想:return
function [out1, out2] = foo(inp1, inp2, inp3)
out1 = inp1 + inp2; % only requires inp1 and inp2
if nargout < 2; return; end
out2 = inp1 + inp2 + inp3; % requires all inputs
end
(这是最好的方法吗?
理想的解决方案也与参数的位置不变。例如:
[~,b] = baz(1, 2);
function [out1, out2] = baz(inp1, inp2, inp3)
out2 = inp1 + inp2; % only requires inp1 and inp2
out1 = inp1 + inp2 + inp3; % requires all inputs
end
也应该运行而不会出错。
答:
您应该将内置的“变量参数输入”(文档在这里)与(文档在这里)和“变量参数输出”(文档在这里)结合使用varargin
nargin
varargout
)
function [out1, varargout] = foo(inp1, inp2, varargin)
if nargin < 3
out1 = inp1 + inp2;
else % only requires inp1 and inp2
out1 = inp1 + inp2;
varargout{1}= inp1 + inp2 + varargin{1};
end
end
和他们一起玩,看看你是否能找到你想要的解决方案。
如果您有很多输入,则需要一些级联。switch-case
if-else
对于与位置无关的主题,可以实现与此类似的想法:
假设执行的操作绑定到 I/O 编号,使得输出 n = 从 1 到 n+1 的总和输入
function varargout=foo(varargin)
if nargin == nargout+1
if nargout >1
historypath = com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory;
cmd= historypath(end);
otps=extractBetween(cmd.toCharArray','[',']');
otps=strsplit(otps{1},',');
else
otps={'pass'};
end
for tt=1:nargout
if strcmp(otps{tt},'~')
varargout{tt}=NaN;
else
varargout{tt}=sum([varargin{1:tt+1}]);
end
end
else
error('Mismatched I/Os')
end
end
此函数分析函数的命令窗口调用以绕过“~”输出。
评论
[~,b]
NaN
如果要避免昂贵的计算来生成未请求的输出,则必须包含对 的检查,没有其他方法可以避免计算。nargout
某些函数产生的输出与输入一样多 - 在这些情况下,使用 和 。但总的来说,如果只能根据提供的输入数量计算特定输出,那么这可能是一个尴尬的设计。varargin
varargout
另一种方法是使用 arguments
块来指定输入参数的默认值。
function [out1, out2] = foo(inp1, inp2, inp3)
arguments
inp1
inp2
inp3 = 0
end
out1 = inp1 + inp2;
out2 = inp1 + inp2 + inp3;
end
评论
arguments
arguments
inputParser
~
您只需检查请求的输出参数的数量,并在需要其他输入以形成未请求的输出之前从函数中检查return
function [out1, out2] = foo(inp1, inp2, inp3)
out1 = inp1 + inp2; % only requires inp1 and inp2
% If only one output is requested then stop here
if nargout < 2
return
end
% More than one output requested, calculate further outputs (requires further inputs)
out2 = inp1 + inp2 + inp3; % requires all inputs
end
这如描述的那样工作,如果你打电话给你得到并且没有错误。a = foo(1,2)
a=3
编辑:从您的评论中,听起来更像是您想为给定的输入填充尽可能多的输出。如果不对调用线路进行某种解析,就无法检测出哪些输出被丢弃(请参阅 MathWorks Answers ref detectoutputsuppression 上的此答案)。因此,一种方法不足以处理这种情况。~
nargout
[~,b] = foo(1,2,3)
因此,在这种情况下,我可能只使用元胞数组作为单个输出:
function out = foo(inp1, inp2, inp3)
out = cell(1,2); % Initialise output with two (empty) elements
out{1} = inp1 + inp2;
if nargin > 2
out{2} = inp1 + inp2 + inp3;
end
end
然后,如果您只需要第二个输出,则可以使用out=foo(1,2,3); out{2}
最后一种选择可能是让第一个输入决定函数的行为,即
function [out1, out2] = foo(nout, inp1, inp2, inp3)
% nout should be 1, 2, or [1,2] depending on the requested outputs to save
% on computation time for undesired outputs
if any(nout == 1)
out1 = inp1 + inp2;
end
if any(nout == 2)
out2 = inp1 + inp2 + inp3;
end
end
这将节省计算不需要的输出,并且相当明确。显然,它需要对调用的行有更多的意识,因为它会像这样使用foo
a = foo( 1, 1, 2 ); % only want output 1
% equivalent to a = foo( 1, 1, 2, 3 )
[~,b] = foo( 2, 1, 2, 3 ); % only want output 2
% No computation time spend on output 1
[a,b] = foo( [1,2], 1, 2 ,3 ); % compute both outputs
[a,b] = foo( [1,2], 1, 2 ); % errors because not enough inputs to compute b
评论
nout
[~,b] = ...
nargout
nout
对于每个输出,创建一个匿名函数,并将它们放在元胞数组中,并用于生成输出:arrayfun
function varargout = foo(varargin)
fcn = { ...
@(inp1, inp2) inp1 + inp2, ...
@(inp1, inp2, inp3) inp1 + inp2 + inp3 ...
};
varargout = arrayfun(1:nargout, @(n){fcn{n}(varargin{:})});
end
如果请求输出,则执行第一个函数。如果请求两个输出,则执行两个函数:
a = foo(1, 2); % only the first function is executed
[a,b] = foo(1, 2, 3); % both functions are executed
请注意,您可以定义本地函数并将其句柄放在元胞数组中,而不是匿名函数:
function out1 = foo2(inp1, inp2)
out1 = inp1 + inp2;
end
function out2 = foo3(inp1, inp2, inp3)
out2 = inp1 + inp2 + inp3;
end
function varargout = foo(varargin)
fcn = {@foo2, @foo3};
varargout = arrayfun(1:nargout, @(n){fcn{n}(varargin{:})});
end
评论
if statement
if
受 Wolfie、Ferro Luca 和 Edric 的启发:我认为另一种解决方案是检查输入参数的存在/空,如果某些值不存在,则提前返回。这样做的一个优点是:(i)它允许检查每个变量;(ii) 如果需要进行多次检查,则不需要嵌套。
function [out1, out2] = baz(inp1, inp2, inp3)
out1 = NaN;
out2 = inp1 + inp2; % only requires inp1 and inp2
if ~exist('inp3', 'var'); return; end % check if data are present for next steps
out1 = inp1 + inp2 + inp3; % requires all inputs
end
评论
[out1, out4] = func(x, y, ['out1','out4'])