在matlab中传递和保存匿名函数

ema*_*rti 9 matlab anonymous-function

我想要一个函数(例如,拟合函数)来返回一个struct我可以保存并稍后使用的匿名函数(通常存储在a中).但是,传递@func往往会传递函数指针而不是函数本身.是一个inline函数来做到这一点的唯一途径?我想避免inline因为它非常慢.

如果这个问题不明确,这里有一个有问题的代码示例:我testFunc.m在一些文件中写了一个文件PATH

    %testFunc.m
    function myfunc = testFunc()
        myfunc = @(x) x.^2;
    end
Run Code Online (Sandbox Code Playgroud)

然后我将函数存储在一个struct.(我知道这应该是一个对象!)

    >> mystruct = struct;
    >> mystruct.func = testFunc()
    >> mstruct.x = [1 2 3];
    >> save('myfile.mat','mystruct')
    >> mystruct.func(mystruct.x)

    ans = 

         1     4     9
Run Code Online (Sandbox Code Playgroud)

如果我然后移动myfile.mattestFunc.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 
Run Code Online (Sandbox Code Playgroud)

我知道有问题因为,如果我检查一下 functions

    >> functions(mystruct.func)

    ans = 

         function: '@(x)x.^2'
             type: 'anonymous'
             file: 'PATH/testFunc.m'
        workspace: {2x1 cell}
Run Code Online (Sandbox Code Playgroud)

有没有办法剥离文件工作区信息?是inline功能唯一的解决办法?

And*_*nke 8

简单案例

如果你想要匿名的函数仅限于根据它们的输入参数定义(比如inline函数),并且你可以承诺在你的路径上保留一个函数,那么你可以制作"消毒"的匿名函数.

function out = sanitized_anon_fcn(str)
out = eval(str);
end
Run Code Online (Sandbox Code Playgroud)

因此,在您希望创建匿名函数的代码中,执行此操作.

%testFunc2.m
function myfunc = testFunc2()
    myfunc = sanitized_anon_fcn('@(x) x.^2');
end
Run Code Online (Sandbox Code Playgroud)

只要sanitized_anon_fcn.m保留在您的路径上,您就可以删除testFunc2,并且保存的功能将继续有效.保存或加载时无需特殊处理.Sanitized_anon_fcn基本上工作,inline但产生的功能与匿名函数一样快(因为它们是匿名函数).在我的电脑上,R2011b的速度差异约为10倍.

一般情况

在一般情况下,函数可能实际使用工作空间中的变量,事情变得棘手.

警告:这是一个病态的黑客,我不认可它在生产代码中的使用.但作为语言如何运作的一个例子,我无法抗拒发布它.

我觉得你已经90%了.但是您需要保留工作区信息而不是将其剥离,因为它可能有助于函数的操作.而不是保存匿名函数句柄,抓住functions()你正在进行的那个调用的输出并保存.

fcn = testFunc();
fcn_info = functions(fcn);
save willbreak.mat fcn
save blah.mat fcn_info
Run Code Online (Sandbox Code Playgroud)

然后加载它.您仍然会收到相同的警告,但现在警告仅适用于在顶级匿名函数的工作空间内捕获的函数句柄.如果您的函数实际上没有引用它们(并且它不应该),您可以忽略该警告并且它将起作用.

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
Run Code Online (Sandbox Code Playgroud)

然后将它传递给类似于此函数的东西,这将使您的匿名函数在具有相同工作空间值的新工作空间中从死区返回,或多或少.

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
Run Code Online (Sandbox Code Playgroud)

在我们的示例中:

fcn = reconstruct_anon_fcn(s.fcn_info)
fcn(2)   % and it works!
Run Code Online (Sandbox Code Playgroud)

现在,所有加载的匿名函数都声称来自这个新文件,但它无关紧要,因为它只是工作空间的快照状态,而不是匿名函数使用的封闭变量.并且在工作空间中存在实际被计算使用的匿名函数句柄的情况下,您将得到一个适当的错误,说"未定义的函数句柄".

这是一个黑客,但也许你可以采取这个并将其扩展到相当强大的东西.