什么是函数句柄,它有什么用处?

38
有人能解释一下 @(函数句柄)运算符的含义以及使用它的原因吗?
3个回答

50

在MATLAB中,函数句柄运算符本质上就像是指向特定函数实例的指针。其他答案已经讨论了它的一些用途,但我在这里补充另一个用途:保持对不再“在范围内”的函数的访问。

例如,以下函数初始化值count,然后返回到嵌套函数increment的函数句柄:

function fHandle = start_counting(count)

  disp(count);
  fHandle = @increment;

  function increment
    count = count+1;
    disp(count);
  end

end

由于函数increment是一个嵌套函数,因此它只能在函数start_counting内部使用(即start_counting的工作区是其“作用域”)。 但是,通过返回对函数increment的句柄,我仍然可以在start_counting之外使用它,并且它仍然保留对start_counting工作区中变量的访问权!这使我能够做到这一点:

>> fh = start_counting(3);  % Initialize count to 3 and return handle
     3

>> fh();  % Invoke increment function using its handle
     4

>> fh();
     5

注意,即使我们在函数 start_counting 外部,仍然可以持续增加计数。但是您甚至可以通过使用不同的数字再次调用start_counting并将函数句柄存储在另一个变量中来做一些更有趣的事情:

>> fh2 = start_counting(-4);
    -4

>> fh2();
    -3

>> fh2();
    -2

>> fh();  % Invoke the first handle to increment
     6

>> fh2();  % Invoke the second handle to increment
    -1

请注意,这两个不同的计数器是独立操作的。函数句柄 fhfh2 指向具有不同工作空间的函数 increment 的不同实例,它们包含唯一的 count 值。

除此之外,结合嵌套函数使用函数句柄还可帮助简化 GUI 设计,就像我在另一个 SO 帖子中所演示的那样。


2
需要注意的一件事是,使用function关键字创建的函数和使用@操作符创建的函数具有不同的作用域规则。hGetCount = @getCount; function c = getCount; c = count; end;在评估时间(使用词法作用域)进行count变量查找,正如您上面所描述的那样。函数hGetCount = @()count;将在创建时替换计数变量的值。 - Mr Fooz
2
函数句柄允许您在主函数外部使用嵌套函数或子函数。它们可以帮助您进行 GUI 编程。 - user85109
@ Mr. Fooz:好观点!使用 @ 运算符创建的匿名函数将简单地为在它们被创建时存在于工作区中的变量替换值,而“普通”函数则有自己的工作区来存储变量。 - gnovice

18

函数句柄是Matlab中非常强大的工具。一个好的开始是阅读在线帮助,这将为您提供比我更多的信息。在命令提示符下,键入

doc function_handle

函数句柄是一种简单的方法,在一行中创建一个函数。例如,假设我希望对函数sin(k*x)进行数值积分,其中k具有某个固定的外部值。我可以使用内联函数,但函数句柄更加简洁。定义一个函数。
k = 2;
fofx = @(x) sin(x*k);

看到我现在可以在命令行上评估函数fofx。 MATLAB知道k是什么,所以我们现在可以将fofx用作函数。

fofx(0.3)
ans =
         0.564642473395035

事实上,我们可以像变量一样有效地传递fofx。例如,让我们调用quad进行数值积分。我将选择区间[0,pi / 2]。
quad(fofx,0,pi/2)
ans =
         0.999999998199215

正如您所看到的,quad 进行了数值积分。(顺便说一下,内联函数至少会慢一个数量级,而且使用起来也不够方便。)

x = linspace(0,pi,1000);
tic,y = fofx(x);toc
Elapsed time is 0.000493 seconds.

通过比较,试试内联函数。
finline = inline('sin(x*k)','x','k');
tic,y = finline(x,2);toc
Elapsed time is 0.002546 seconds.

函数句柄的一个好处是可以即时定义。如何在区间[0,2*pi]上最小化cos(x)函数?
xmin = fminbnd(@(x) cos(x),0,2*pi)
xmin =
          3.14159265358979

在MATLAB中,函数句柄还有许多其他用途。我在这里只是浅尝辄止。


15

免责声明:代码未经测试...

函数句柄运算符允许您创建对函数的引用,并像任何其他变量一样传递它:

% function to add two numbers
function total = add(first, second) 
    total = first + second;
end

% this variable now points to the add function
operation = @add;

一旦你有了一个函数句柄,你可以像调用普通函数一样调用它:

operation(10, 20); % returns 30

函数句柄的一个好处是,你可以像对待其他数据一样传递它们,因此你可以编写操作其他函数的函数。这通常使得你可以轻松地分离业务逻辑:

% prints hello
function sayHello 
    disp('hello world!');
end

% does something five times
function doFiveTimes(thingToDo) 
    for idx = 1 : 5 
        thingToDo();
    end
end

% now I can say hello five times easily:
doFiveTimes(@sayHello);

% if there's something else I want to do five times, I don't have to write
% the five times logic again, only the operation itself:
function sayCheese 
    disp('Cheese');
end
doFiveTimes(@sayCheese);

% I don't even need to explicitly declare a function - this is an 
% anonymous function:
doFiveTimes(@() disp('do something else'));

Matlab文档提供了更详细的Matlab语法说明,并描述了函数句柄的其他用途,如图形回调。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接