"Undefined" 重写但未重新定义已定义的函数时出错
"Undefined" error for rewriting but not redefining an already defined function
这有效(绘制 "empty" 图):
function testme
plot(1)
这个有效(returns 1):
function testme
plot = @(x)x;
plot(1)
这不是(错误:"Undefined function or variable 'plot'."):
function testme
if 0
plot = @(x)x;
end
plot(1)
这是怎么回事?为什么重写而不是重新定义一个已经定义的函数会导致函数未定义?
注1:这不是内置函数特有的;下面的代码return同样的错误:
function testme
if 0
myfun = @(x)x;
end
myfun(1)
function x=myfun(x)
x=x*2;
注2:错误发生在函数环境中,而不是脚本中;以下代码不会 return 错误(并绘制与第一个示例中相同的空图形):
if 0
plot = @(x)x;
end
plot(1)
Update: For the interested reader, here is some background information
on my original problem. The above examples are just minimum working
samples to illustrate the main issue (which indeed feature dead end if
statements). In practice, I was trying to make a function useable for
colleagues who did not have certain library/toolbox functions
available, by overwriting those functions for simplified custom ones
if they did not exist, as a quick fix. In particular, it concerned
imdilate (and imerode). The function looked something like the
following:
function [myoutputs] = myfunction(myinputs)
% if the images toolbox is not available, use the following simplified
% replacement function
if ~exist('imdilate','file')
imdilate = @(IM,SE)vecdilate(IM,SE);
end
%% The original function goes here, which uses a lot of imdilate(IM,SE).
%% local functions
function M = vecdilate(IM,SE)
% simplified version of imdilate (can only process 1-D vertical arrays)
nSE = size(SE);
nIM = size(IM);
SE = logical(SE); % make logical if it isn't yet
% copy and shift xth column x down. new border entries are 0:
M = repmat([IM;zeros(nSE)],nSE);
M = M(1:end-nSE(1));
M = reshape(M,[size(M,1)/nSE(1) nSE(1)]);
% shrink back to column by taking max of every row:
M = max(M(:,SE),[],2);
M = M(ceil(nSE(1)/2)-1+(1:nIM(1))); % clip to obtain correct size
You might see that the replacement function covers some
functionality of imdilate, but not all, and it might not be as
efficient. The purpose simply was to use function A if it was available, and
function B if it was not. To my surprise however, the former case
returned an error, which eventually resulted in this question. For your interest, I solved the practical problem by renaming the function in the
original code, and by using an if/else statement:
function [myoutputs] = myfunction(myinputs)
% if the images toolbox is not available, use the following simplified
% replacement function
if ~exist('imdilate','file')
mydilate = @(IM,SE)vecdilate(IM,SE);
else
mydilate = @(IM,SE)imdilate(IM,SE);
end
%% The original function goes here, which uses a lot of mydilate(IM,SE).
%% local functions
function M = vecdilate(IM,SE)
etc. etc. etc.
Just-in-time-compilation (JIT) 并不意味着没有编译,每一行都被单独解释,所以你仍然可以乱码;)
如果您使用未定义的函数也会出现该错误,您甚至不会期望代码为 运行,例如
function [] = test()
if false
a = @(x)x;
end
a(1)
end
脚本是存储的命令行条目,即编译器别无选择,只能单独处理每一行(您可能想将其视为键盘宏)。
相反,函数是封装的代码片段。编译器(通常)不会期望任何未知的东西 + 它认为这段封装的代码可能会被重用。因此,它确保正确地预先编译所有代码一次(如果编译一直这样做,则称为提前编译)。
当您清除两者之间的变量时,这一点变得尤为明显:
function [] = test()
if false
plot = @(x)x;
else
clear all % clear vs clear all
end
plot(1)
end
(请注意 clear
清除所有变量,但 clear all
也会清除切除代码(参见 MATLAB Execution Engine))
看看这个来自 Loren
的有趣 blog post
MATLAB provides the best of both worlds by compiling MATLAB code on-the-fly, or just-in-time. MATLAB code is compiled whether it be in classes, functions, scripts, or simply at the command line. There is no explicit compile step for the user to initiate and MATLAB code can be executed in blocks as small as one line at a time. The MATLAB JIT compiler generates native machine level code that is optimized for the MATLAB code being executed and for the specific hardware platform.
无论如何,您不应该在代码中写死胡同或覆盖(本机)函数。最好使用函数句柄来克服这个问题,但请确保为所有情况定义它
function [] = test()
if false % dead end definition
fnc = @(x)x;
else
fnc = @plot;
end
fnc(1)
end
这有效(绘制 "empty" 图):
function testme
plot(1)
这个有效(returns 1):
function testme
plot = @(x)x;
plot(1)
这不是(错误:"Undefined function or variable 'plot'."):
function testme
if 0
plot = @(x)x;
end
plot(1)
这是怎么回事?为什么重写而不是重新定义一个已经定义的函数会导致函数未定义?
注1:这不是内置函数特有的;下面的代码return同样的错误:
function testme
if 0
myfun = @(x)x;
end
myfun(1)
function x=myfun(x)
x=x*2;
注2:错误发生在函数环境中,而不是脚本中;以下代码不会 return 错误(并绘制与第一个示例中相同的空图形):
if 0
plot = @(x)x;
end
plot(1)
Update: For the interested reader, here is some background information on my original problem. The above examples are just minimum working samples to illustrate the main issue (which indeed feature dead end if statements). In practice, I was trying to make a function useable for colleagues who did not have certain library/toolbox functions available, by overwriting those functions for simplified custom ones if they did not exist, as a quick fix. In particular, it concerned imdilate (and imerode). The function looked something like the following:
function [myoutputs] = myfunction(myinputs) % if the images toolbox is not available, use the following simplified % replacement function if ~exist('imdilate','file') imdilate = @(IM,SE)vecdilate(IM,SE); end %% The original function goes here, which uses a lot of imdilate(IM,SE). %% local functions function M = vecdilate(IM,SE) % simplified version of imdilate (can only process 1-D vertical arrays) nSE = size(SE); nIM = size(IM); SE = logical(SE); % make logical if it isn't yet % copy and shift xth column x down. new border entries are 0: M = repmat([IM;zeros(nSE)],nSE); M = M(1:end-nSE(1)); M = reshape(M,[size(M,1)/nSE(1) nSE(1)]); % shrink back to column by taking max of every row: M = max(M(:,SE),[],2); M = M(ceil(nSE(1)/2)-1+(1:nIM(1))); % clip to obtain correct size
You might see that the replacement function covers some functionality of imdilate, but not all, and it might not be as efficient. The purpose simply was to use function A if it was available, and function B if it was not. To my surprise however, the former case returned an error, which eventually resulted in this question. For your interest, I solved the practical problem by renaming the function in the original code, and by using an if/else statement:
function [myoutputs] = myfunction(myinputs) % if the images toolbox is not available, use the following simplified % replacement function if ~exist('imdilate','file') mydilate = @(IM,SE)vecdilate(IM,SE); else mydilate = @(IM,SE)imdilate(IM,SE); end %% The original function goes here, which uses a lot of mydilate(IM,SE). %% local functions function M = vecdilate(IM,SE) etc. etc. etc.
Just-in-time-compilation (JIT) 并不意味着没有编译,每一行都被单独解释,所以你仍然可以乱码;)
如果您使用未定义的函数也会出现该错误,您甚至不会期望代码为 运行,例如
function [] = test()
if false
a = @(x)x;
end
a(1)
end
脚本是存储的命令行条目,即编译器别无选择,只能单独处理每一行(您可能想将其视为键盘宏)。 相反,函数是封装的代码片段。编译器(通常)不会期望任何未知的东西 + 它认为这段封装的代码可能会被重用。因此,它确保正确地预先编译所有代码一次(如果编译一直这样做,则称为提前编译)。
当您清除两者之间的变量时,这一点变得尤为明显:
function [] = test()
if false
plot = @(x)x;
else
clear all % clear vs clear all
end
plot(1)
end
(请注意 clear
清除所有变量,但 clear all
也会清除切除代码(参见 MATLAB Execution Engine))
看看这个来自 Loren
的有趣 blog postMATLAB provides the best of both worlds by compiling MATLAB code on-the-fly, or just-in-time. MATLAB code is compiled whether it be in classes, functions, scripts, or simply at the command line. There is no explicit compile step for the user to initiate and MATLAB code can be executed in blocks as small as one line at a time. The MATLAB JIT compiler generates native machine level code that is optimized for the MATLAB code being executed and for the specific hardware platform.
无论如何,您不应该在代码中写死胡同或覆盖(本机)函数。最好使用函数句柄来克服这个问题,但请确保为所有情况定义它
function [] = test()
if false % dead end definition
fnc = @(x)x;
else
fnc = @plot;
end
fnc(1)
end