Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 什么时候可以传递函数句柄?_Matlab_Namespaces_Stack_Function Handle_Matlab Class - Fatal编程技术网

Matlab 什么时候可以传递函数句柄?

Matlab 什么时候可以传递函数句柄?,matlab,namespaces,stack,function-handle,matlab-class,Matlab,Namespaces,Stack,Function Handle,Matlab Class,我有一个用于缓存计算的函数。作为参数之一,它接受一个函数句柄。在某些情况下,函数句柄是不可访问的,我不太明白为什么。下面的示例显示了让我感到困惑的原因: >> A.a = @plus; feval(@A.a, 1, 1) ans = 2 >> clear A >> A.a.a = @plus; feval(@A.a.a, 1, 1) Error using feval Undefined function 'A.a.a' for input a

我有一个用于缓存计算的函数。作为参数之一,它接受一个函数句柄。在某些情况下,函数句柄是不可访问的,我不太明白为什么。下面的示例显示了让我感到困惑的原因:

>> A.a = @plus; feval(@A.a, 1, 1)

ans =

     2

>> clear A
>> A.a.a = @plus; feval(@A.a.a, 1, 1)
Error using feval
Undefined function 'A.a.a' for input arguments of type 'double'.
所以,如果我有一个作为结构成员存储的函数句柄,如果它有一层深度,我可以很好地传递它,但是如果它有两层深度,我就不能传递它。在我的实际用例中,我有一个结构
D
,它包含许多(117)个不同类的实例,所以我实际上有
stct.obj.meth
,其中
stct
是一个结构,
obj
是一个类实例/对象,
meth
是一个方法。传递
@stct.obj.meth
失败,但如果我分配
A=stct.obj
,则传递
@A.meth
成功

在什么条件下,我可以将函数句柄作为参数传递,以便它仍然可以在堆栈中访问


Edit:尽管在上面的用例中,我可以简单地删除
@
,因为
@plus
已经是一个函数句柄。但是,考虑一下这里的情况:

>> type cltest.m

classdef cltest < handle
    methods
        function C = mymeth(self, a, b)
            C = a + b;
        end
    end
end

>> A.a = cltest();
>> feval(@A.a.mymeth, 1, 1)
Error using feval
Undefined function 'A.a.mymeth' for input arguments of type 'double'.
>> b = A.a;
>> feval(@b.mymeth, 1, 1)

ans =

     2
>类型cltest.m
classdef cltest<句柄
方法
函数C=mymeth(self,a,b)
C=a+b;
结束
结束
结束
>>A.A=cltest();
>>feval(@A.A.mymeth,1,1)
使用feval时出错
类型为“double”的输入参数的未定义函数“A.A.mymeth”。
>>b=A.A;
>>feval(@b.mymeth,1,1)
ans=
2.
在这种情况下,我需要在A.A.mymeth之前使用
@

试试这个:

feval(@(varargin)A.a.mymeth(varargin{:}),1,1);
这有点麻烦,但应该行得通

编辑:

它的工作方式是创建一个接受可变数量参数的,并将这些参数转储到方法
a.a.mymeth()
。因此,实际上并不是传递指向函数a.a.mymeth的指针,而是传递指向调用
a.a.mymeth
的函数的指针

不使用
varargin
实现相同目标的另一种方法是:

feval(@(x,y)A.a.mymeth(x,y),1,1);
这将创建一个接受两个参数的匿名函数,并将它们传递给
A.A.mymeth

我认为这一定是一元函数处理运算符
@
的固有方式。Matlab解析器可能会查看
@token
,并决定
token
是否为有效函数。在
a.mymeth
的情况下,它足够聪明,可以确定
mymeth
a
的成员,然后返回相应的句柄。但是,当它看到
A.A.mymeth
时,可能会发现
A
不是一个类,
A
也没有名为
A.mymeth
的成员,因此找不到有效的函数。这似乎得到了以下事实的支持:

A.a.a = @plus; feval(A.a.a,1,1)
但这并不是:

A.a.a = @plus; feval(@A.a.a,1,1)

引入类对MATLAB来说是一件大事。事实上,它们太大了,以至于今天仍然不能正常工作。您的示例显示,结构访问和类方法访问冲突,因为它们必须重载点“.”的含义,并且无法使其无缝工作。当您在MATLAB控制台上以类方法的名称显式地调用类方法时,它或多或少都可以正常工作,例如,在您的示例中>>A.A.mymeth(1,1)。但是,当你有任何类型的间接,它很快就会打破

您尝试通过
>@A.A.mymeth
获取函数句柄,这是MATLAB无法理解的,可能是因为它被混合结构/类混淆了。尝试使用
str2func
解决问题也不起作用。同样,它只对显式名称访问有效,如图所示。对于您的示例,它会中断,例如,
>str2func('b.mymeth')
。它甚至在课堂上都不起作用。尝试其他间接方法并看着它们失败

另外,MATLAB不喜欢给你一个类方法的句柄。它没有任何功能。无法一次获取所有函数句柄,甚至无法通过名称字符串动态获取所有函数句柄

我在这里看到三种选择。首先,如果可能,尝试更改您的程序。这些函数是否需要放在classdef中

其次,遵循您或nispio的解决方法。它们都创建一个临时变量来保存对类实例的引用,以便创建对其成员方法的非混合访问。问题是,它们都需要显式地命名函数。您必须为涉及的每个函数显式地放入此代码。没有办法把它抽象出来

第三,通过从内部给出类的方法句柄来作弊。你可以在一个结构中给出它们

classdef cltest < handle
    methods
        function C = mymeth(self, a, b)
            C = a + b;
        end
        function hs = funhandles(self)
            hs = struct('mymeth', @self.mymeth, ...
                        'mymeth2', @self.mymeth2);
        end
    end
end

但要小心,通过使用此选项,您可以从外部访问access=private方法。

您可以通过引入一个单独的函数来解决此问题,该函数可以纠正
@
操作员没有执行的操作:

function h=g(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']);
else
    h = f;
end
end
现在以您为例:

>> feval(g(@A.a.mymeth), 1, 1)
ans =
     2
>> feval(g(@b.mymeth), 1, 1)
ans =
     2
我认为这对代码的影响最小。您可以使其更加优雅,但不那么健壮和/或可读。没有为
function\u handle
类定义
uplus
方法,因此您可以在路径中的某个位置使用以下内容在文件夹
@function\u handle
中创建
uplus.m

function h=uplus(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']);
else
    h = f;
end
end
现在您只需要使用
+@
而不是
@
。举个例子:

>> feval(+@A.a.mymeth, 1, 1)
ans =
     2
>> feval(+@b.mymeth, 1, 1)
ans =
     2

我不认为它比我自己的
B=A.A;feval(@b.mymeth,1,1)
。问题是:这里发生了什么?你必须小心你展示的解决方法,因为如果你在调用
feval
之前覆盖了b,那么你就有问题了。有关我的解决方案工作原理的解释,请参见我的文章编辑。我没有很好的解释为什么
@a.a.mymeth
不能生成有效的函数句柄,但值得注意的是,在第一个示例中,不需要额外的
@
。你可以使用
A.A=@plus;费瓦尔(A.A.1,1)A.A
已经是函数指针。
>> feval(+@A.a.mymeth, 1, 1)
ans =
     2
>> feval(+@b.mymeth, 1, 1)
ans =
     2