我想要一个函数(例如,fit 函数)返回一个匿名函数(通常存储在 struct
中),我可以保存并在以后使用。但是,传递 @func
倾向于传递函数指针而不是函数本身。 inline
函数是执行此操作的唯一方法吗?我想避免 inline
因为它非常慢。
如果这个问题不清楚,这里有一个有问题的代码示例:我在一些 PATH
testFunc.m
文件
%testFunc.m
function myfunc = testFunc()
myfunc = @(x) x.^2;
end
然后我将函数存储在 struct
中。 (我知道这真的应该是一个对象!)
>> mystruct = struct;
>> mystruct.func = testFunc()
>> mstruct.x = [1 2 3];
>> save('myfile.mat','mystruct')
>> mystruct.func(mystruct.x)
ans =
1 4 9
如果我随后移动 myfile.mat
或 testFunc.m
并加载 myfile.mat
,我将无法加载旧结构。相反,我收到错误:
>> cd 'otherdir'
>> load('../myfile.mat')
Warning: Could not find appropriate function on path
loading function handle PATH/testFunc.m>@(x)x.^2
我知道有问题,因为如果我检查函数
>> functions(mystruct.func)
ans =
function: '@(x)x.^2'
type: 'anonymous'
file: 'PATH/testFunc.m'
workspace: {2x1 cell}
有没有办法去除文件工作区信息? inline
函数是唯一的解决方案吗?
最佳答案
简单案例
如果您希望匿名的函数仅限于根据它们的输入参数定义(例如 inline
函数),并且您可以 promise 在您的路径中保留一个函数,那么您可以制作“经过 sanitizer 的”匿名函数。
function out = sanitized_anon_fcn(str)
out = eval(str);
end
因此,在您的代码中,如果您想创建一个匿名函数,请执行此操作。
%testFunc2.m
function myfunc = testFunc2()
myfunc = sanitized_anon_fcn('@(x) x.^2');
end
只要 sanitized_anon_fcn.m 留在你的路径上,你就可以删除 testFunc2,保存的函数将继续工作。保存或加载时无需特殊处理。 Sanitized_anon_fcn
基本上像 inline
一样工作,但生成的函数与匿名函数一样快(因为它们是匿名函数)。在我的计算机上,R2011b 的速度差异约为 10 倍。
一般情况
在一般情况下,函数实际上可能会使用其工作区中的变量,事情会变得更加棘手。
警告:这有点恶心,我不赞成在生产代码中使用它。但作为该语言如何工作的示例,我忍不住将其发布。
我认为您已经完成了 90%。但是您需要保留工作区信息而不是将其剥离,因为它可能有助于函数的运行。不要保存匿名函数句柄,而是获取您正在进行的 functions()
调用的输出并保存 that。
fcn = testFunc();
fcn_info = functions(fcn);
save willbreak.mat fcn
save blah.mat fcn_info
然后加载回来。您仍然会收到相同的警告,但现在警告仅适用于在顶级匿名函数的工作区内捕获的函数句柄。如果您的函数实际上没有引用它们(而且它不应该),您可以忽略警告,它会起作用。
s0 = load('willbreak.mat') % will warn and return unusable function
warning off MATLAB:dispatcher:UnresolvedFunctionHandle
s = load('blah.mat') % will warn, but the first-level function will be usable
warning on MATLAB:dispatcher:UnresolvedFunctionHandle
然后将它传递给类似于此函数的函数,这将使您的匿名函数在新工作区中起死回生,新工作区具有相同的工作区值,或多或少。
function out = reconstruct_anon_fcn(s)
for iWks = 1:numel(s.workspace)
wkspace = s.workspace{iWks};
varnames = fieldnames(wkspace);
for i = 1:numel(varnames)
tmp = wkspace.(varnames{i});
eval([varnames{i} ' = tmp;']);
end
end
fcn_str = s.function;
fcn = eval(fcn_str);
out = fcn;
end
在我们的例子中:
fcn = reconstruct_anon_fcn(s.fcn_info)
fcn(2) % and it works!
现在,所有加载的匿名函数都将声称来自这个新文件,但这无关紧要,因为匿名函数使用的只是工作区的快照状态,而不是封闭变量。如果工作区中存在计算实际使用的匿名函数句柄,您将收到一条相应的错误消息“未定义的函数句柄”。
这是一个 hack,但也许您可以将其扩展为相当稳健的东西。
关于matlab - 在matlab中传递和保存匿名函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9285725/