背景知识-我正在阅读有关访问阴影函数的信息,并开始使用builtin
。我写了一个小函数:
function klear(x)
% go to parent environment...
evalin('base', builtin('clear','x')) ;
end
这会引发错误:
Error using clear
Too many output arguments.
我认为发生这种情况是因为evalin
要求从所馈送的内容中获取任何输出,但是clear
是没有返回值的函数之一。
有两个问题:我是否正确地解释了这个问题;如果是,是否有替代函数可以让我在父环境中执行一个函数(不需要输出)?
注意:我完全知道反对尝试访问带阴影的函数(或者避免以重载基本函数等方式命名函数)的论点。这主要是一个问题,可以帮助我了解MATLAB中可以做什么和不能做什么。
我最初的目标是编写一个需要输入参数的重载函数,以避免clear
的恶意行为,该行为默认为删除所有内容。在Q&D伪代码中,
function clear(x)
if ~exist('x','var') return
execute_in_base_env(builtin(clear(x)))
end
答案 0 :(得分:2)
代码中会发生什么:
evalin('base', builtin('clear','x'));
是builtin
是在当前上下文中求值的,并且因为它用作evalin
的参数,所以预期会产生输出。完全相同:
ans = builtin('clear','x');
evalin('base',ans);
您看到的错误消息出现在这两行代码的第一行,而不是第二行。并不是因为evalin
确实支持不产生输出参数的调用语句。
evalin
需要一个字符串来求值。您需要构建以下字符串:
str = 'builtin(''clear'',''x'')';
evalin('base',ans);
(在MATLAB中,将引号字符加倍即可将其转义。)
您的功能将如下所示:
function clear(var)
try
evalin('base',['builtin(''clear'',''',var,''')'])
catch
% ignore error
end
end
(以这种方式将一个字符串插入另一个字符串相当尴尬,这是我不喜欢eval
和朋友的众多原因之一。)
在这种情况下,最好使用evalin('caller',...)
,这样,当您从函数中调用新的clear
时,它将删除函数工作区中的某些内容,而不是基本工作区中的某些内容。我认为'base'
仅应在可控制用户工作区中变量的GUI中使用,而不应从可以在任何地方调用且应被期望(在这种情况下使用其名称)可以在本地执行的功能中使用
有某些理由可能使它真正有用,但是总的来说,您应该尽量避免使用clear
,就像使用eval
和朋友一样。 clear
会降低程序执行速度。 (在用户和MATLAB JIT上)将一个空数组分配给变量以从内存中删除其内容要容易得多(如rahnema1 in a comment所建议。如果您还使用function
:编写函数,而不是脚本!
答案 1 :(得分:2)
您的clear
覆盖有几个问题:
clear
在基本工作区中。相反,我会检查它是否从基本工作区中调用,并以特殊情况检查它是否清除了所有内容。如果某个函数正在调用普通clear
来清除其所有变量,那是不好的做法,但这仍然是该函数逻辑的工作方式,并且您不想破坏它。否则可能会出错,或更糟的是,返回错误的结果。
所以,像这样:
function clear(varargin)
stk = dbstack;
if numel(stk) == 1 && (nargin == 0 || ismember('all', varargin))
fprintf('clear: balking at clearing all vars in base workspace. Nothing cleared.\n');
return;
end
% Check for quoting problems
for i = 1:numel(varargin)
if any(varargin{i} == '''')
error('You have a quote in one of your args. That''s not valid.');
end
end
% Construct a clear() call that works with evalin()
arg_strs = strcat('''', varargin, '''');
arg_strs = [{'''clear'''} arg_strs];
expr = ['builtin(' strjoin(arg_strs, ', '), ')'];
% Do it
evalin('caller', expr);
end
我希望不言而喻,这是我不建议在实践中使用的骇人听闻的技巧。 :)