2

我有一个存储匿名函数的文件 funcs.m。它们必须可供其所在目录中的文件使用。目前,我使用匿名函数以便funcs.m在不同的文件中执行文件,但我认为这是一种错误的做事方式。其他函数如 main.m 及其嵌套函数 nest.m 需要使用 funcs.m 中的匿名函数。我认为路径不会解决这个问题,因为文件在同一个文件夹中。基本上,我可以通过将匿名函数复制粘贴到每个文件来解决这个问题,但代码气味如此:

是否有某种方法可以重用在 Matlab 中具有匿名函数的 funcs.m?

例子

主文件

function main
funcs; % loads the anonymous functions
nest(par1,...,parN)
end

巢.m

function nest(par1,...,parN)
funcs; %ERRR: This fires err, why? Look: this was sourced already in main.m!
function neededOnlyHere(par100)
    bq(q,A) %This needs the functions of the funcs
end

neededOnlyHere(somePar) %ERR to use the anon funcs from funcs
end

函数 main.m 和 nest.m 使用这个具有匿名函数的函数 funcs.m

bq=@(q,A) q*A;                              %Bolded q
I=@(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0); 
AiNotj=zeros(1,Ncut);                       
...

错误

Attempt to add "bq" to a static workspace.
 See MATLAB Programming, Restrictions on
 Assigning to Variables for details.

Error in funcs (line 10)
bq=@(q,A) q*A;
%Bolded q
4

2 回答 2

6

为什么会破

调用它时会出现错误,nest.m因为嵌套函数使其封闭函数的工作区成为“静态工作区”;也就是说,不能通过 、 或其他“动态”技术添加变量eval()assignin();仅允许在该函数的文本中明确分配的变量。评估脚本以定义局部变量 - 这是您在调用时所做的funcs.m- 是“动态的”,因此在具有嵌套函数的函数中被禁止。它之所以起作用,main.m是因为 main 没有嵌套函数,因此是一个“动态”工作区。

有几种方法可以将其更改为使用静态工作区和嵌套函数。首先要问的是你是否真的需要让它们成为匿名函数?

改用包函数

如果您不需要它们本身是匿名函数,只需将它们分解并将每个作为常规函数放在自己的.m文件中即可;例如bg.m, I.m, AiNotj.m, 等等。然后它们都可用于该目录中的所有其他功能。

如果这变成了一堆文件,或者如果你想限定它们的范围,并且可能只让它们对真正需要它们的选定函数可用(即,当前调用的函数funcs()),那么你可以将它们放在一个包中。创建一个名为的子目录+myfuncs并将所有的小函数文件移到那里;例如+myfuncs/bq.m, +myfuncs/I.m, +myfuncs/AiNotj.m. (+前缀告诉 Matlab 目录是一个包。)然后您可以将它们全部拉入您的函数范围,import myfuncs.*直接替换您当前调用funcs()的 .

function nest(par1,...,parN)
import myfuncs.*;
function neededOnlyHere(par100)
    bq(q,A) % This will work, resolving to myfuncs.bq
end

您也可以import myfuncs.*从命令行执行,以使它们也以交互方式可用。

这可能是 Matlab 本身希望您像这样组织相关函数集群的方式,这将是我的第一种方法。这是最不“臭”的恕我直言。如果您真的希望能够在单个文件中编辑它们,就像funcs.m为了方便一样,您可以在 Perl 或任何解析 funcs.m 的东西中编写一个小代码 munger,并将它们作为预处理步骤作为等效的单个函数输出。(我认为你不能像这样在 M 文件中定义多个顶级函数有点令人遗憾,但是哦。)

如果你真的需要使用匿名函数,有一些解决方法。

在结构中传递函数

您可以更改 funcs() 函数以实际返回所有这些匿名函数的结构,使用字段名称而不是局部变量名称。

function out = funcs
out.bq=@(q,A) q*A;                              %Bolded q
out.I=@(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0); 
out.AiNotj=zeros(1,Ncut);                       

为此,您必须在所有函数引用的前面加上您保存它们的结构名称。不知道这对您来说有多大意义。

function nest(par1,...,parN)
fs = funcs;
function neededOnlyHere(par100)
    fs.bq(q,A) %This needs the functions of the funcs
end

预分配变量

要让 funcs() 按原样工作,您可以使用您要使用的所有函数名称静态预分配变量,因此 Matlab 解析器将它们识别为静态分配的变量。然后当您调用 funcs() 时,它将重新分配现有变量的值,这在动态工作区中是允许的。

function nest(par1,...,parN)
[bq, I, AiNotj] = deal();  % Preallocate all names from funcs
funcs;
function neededOnlyHere(par100)
    bq(q,A) %This needs the functions of the funcs
end

这会有点痛苦,因为每当添加新的函数名称时,您都必须重新编辑每个使用 funcs 的文件。您至少可以编写一个小 perl 脚本,通过解析funcs.m和输出“[bg, I, AiNotj,...] = deal();”来自动生成那行代码。使用它找到的所有功能,您只需将其复制到您的代码中即可。

另一种方法是让 funcs 实际上返回其输出列表中的所有函数。funcs.m只要您不删除或更改现有匿名函数的顺序,这将有利于即使您向 中添加新函数也能继续工作。

function [bg,I,AiNotj] = funcs()
bg = ...
I = ...

% And then in the calling functions:
[bg,I,AiNotj] = funcs(); % which you can copy and paste from funcs.m's header
于 2013-06-08T03:13:43.163 回答
1

传递匿名函数的方式有很多种:

1)传递函数本身:

function main
f = @(t) t^2 - 3;
param = randn(12,1);
g = test22(param,f);
disp (g)
end

function g = test22(param,f)
g = f(param(2));
disp(param(2))
end

2) 使用全局变量(在复杂代码中通常应避免使用)

function main
global f
f = @(t) t^2 - 3;
param = randn(12,1);
g = test22(param);
disp (g)
end

function g = test22(param)    
global f
g = f(param(2));
disp(param(2))
end
于 2013-06-07T02:10:55.827 回答