我正在尝试理解MATLAB脚本的以下命令:
global operatorObj
calcEVR_handles = operatorObj.calcEVR_handles;
m = operatorObj.nInputs
E = zeros(m,1);
V = zeros(m,1);
R = zeros(m,m);
for i=1:m
[E(i), V(i), R(i,i)] = calcEVR_handles{i}(t,x);
end
如果calcEVR_handles
是浮点数且t
是向量,那么x
可以是什么?
答案 0 :(得分:6)
calcEVR_handles
(对我来说)看起来像一个单元格数组,其中每个元素都是函数的句柄。 calcEVR_handles
中的每个元素都是一个匿名函数,它接收单个值t
和单个向量x
。因此,通过执行calcEVR_handles{i}
,您将访问存储在单元阵列中的i th 元素的相应函数。一旦您有权访问,您就可以将参数传递给此函数,它会为您提供这三个输出。
为了向您展示此工作的示例,请考虑以下与calcEVR_handles
类似的单元格数组。
calcCellFunc = {@sin, @cos, @tan};
这是一个三元素单元格数组,其中每个元素都是函数的句柄。 @
是MATLAB中的一个特殊字符,表示您正在创建函数句柄。它也用于创建匿名函数,但让我们搁置这个答案。如果您想深入了解有关此问题的详细信息,可以阅读更多相关内容here。
回到我们的句柄单元格数组,我们将为sin
,cos
和tan
创建句柄。然后,您可以通过calcCellFunc{idx}
访问所需的函数来迭代单元数组,其中idx
是单元数组中所需的元素。这最终将为您提供存储在索引idx
的功能。一旦你这样做,你就可以调用该函数并指定你想要的任何输入(如果不接受任何输入,则指定任何输入)。这是一个快速的例子。让我们创建一个随机的5 x 5矩阵,并以此矩阵作为输入运行每个函数。然后,我们将这些输出中的每一个输出并存储到输出单元阵列中的相应插槽中。就这样:
rng(123); %// Set seed for reproducibility
M = rand(5);
calcCellFunc = {@sin, @cos, @tan};
out = cell(1, numel(calcCellFunc)); %// To store the results for each function
for idx = 1 : numel(calcCellFunc)
out{idx} = calcCellFunc{idx}(M); %// Get the function, then pass
%// the matrix M to it
end
如果您想明确说明,可以将out
语句拆分为:
func = calcCellFunc{idx}; %// Get access to the function
out{idx} = func(M); %// Pass M to this function
如果你是处理/匿名函数的新手,你应该首先使用上面的代码来明确说明MATLAB在做什么。您首先访问存储在单元格数组中的所需函数,然后将参数传递给此函数。
如果我们显示输出,我们得到:
>> celldisp(out)
out{1} =
0.6415 0.4106 0.3365 0.6728 0.5927
0.2823 0.8309 0.6662 0.1815 0.7509
0.2249 0.6325 0.4246 0.1746 0.6627
0.5238 0.4626 0.0596 0.5069 0.5737
0.6590 0.3821 0.3876 0.5071 0.6612
out{2} =
0.7671 0.9118 0.9417 0.7398 0.8054
0.9593 0.5564 0.7458 0.9834 0.6604
0.9744 0.7745 0.9054 0.9846 0.7489
0.8518 0.8866 0.9982 0.8620 0.8191
0.7522 0.9241 0.9218 0.8619 0.7502
out{3} =
0.8363 0.4503 0.3573 0.9094 0.7359
0.2942 1.4934 0.8932 0.1845 1.1370
0.2308 0.8167 0.4690 0.1773 0.8850
0.6149 0.5218 0.0597 0.5880 0.7004
0.8761 0.4135 0.4205 0.5884 0.8814
输出单元格数组的第一个元素在M
传递给sin
时有输出,第二个是M
传递给cos
时的输出,第三个元素是您将M
传递给tan
。
这种代码编写非常有用,因为如果你想使用相同的输入并将它们提供给许多不同的函数,我们自然会倾向于进行一些复制和粘贴。获取每个函数名称,并为每个函数名称创建一行。每一行都会调用你想要的相应函数,然后是输入参数。这可能变得相当繁琐,因此一种聪明的方法是将您的函数名称作为句柄放入单元格数组中,并编写一个{strong 1>}循环遍历所有动态的功能。您甚至可以探索cellfun
并使用for
循环来遍历所有函数句柄,但我会留下让您阅读。
通过这种方式,您可以使用非常易于维护的代码,如果要删除不需要运行的函数,只需从单元格数组中删除句柄,而不是向下滚动到调用此函数的行所在的位置,然后将其删除。
这实际上是计算机科学/软件工程中非常常见的技术。实际上,这实际上与所谓的function pointers非常接近。这是MATLAB的廉价方式,但这背后的逻辑基本相同。
另一种有用的方法是,如果你有一个函数,其中一个(或多个!)输入是一个函数,你也可以指定此函数的输入作为此函数的附加参数功能。这就是所谓的higher order function。输出将基于使用此输入函数,您为其指定的附加输入和输出基于使用此输入函数和您为此函数指定的输入。
一个非常好的例子是MATLAB中的fzero
函数。目标是找到非线性函数的根,第一个参数是您指定的函数的句柄。 for
工作原理背后的基本行为与无关,无论函数是什么。您所要做的就是指定要解决的函数以及您认为该根位置的初始猜测。
总而言之,匿名函数非常有用。