找回密码
 注册
Simdroid-非首页
查看: 98|回复: 9

嵌套函数是否存在必须指定输入参数或函数返回值的例子

[复制链接]
发表于 2013-9-17 03:22:50 | 显示全部楼层 |阅读模式 来自 加拿大
本帖最后由 winner245 于 2013-9-17 08:16 编辑

众所周知,嵌套函数(nested function)可以访问其父函数(凡是包含了该嵌套函数定义的所有上层函数)里的所有变量,父函数可以通过逐层调用嵌套函数来获取嵌套函数任何变量。这是否意味着:

1. 我们没有必要给嵌套函数任何输入参数
2. 我们没有必要让嵌套函数返回任何变量

如果以上2个论述是错误的,最好能举一个必须为嵌套函数使用输入参数或返回值的例子(也就是说,除了使用输入参数或返回值,别无他法)
发表于 2013-9-17 09:48:50 | 显示全部楼层 来自 北京
Simdroid开发平台
我觉得嵌套函数最重要的在于参数共享和传递,是对全局变量的一种改进,变量声明为全局,那么它的作用域就太大了。嵌套函数提供了一种认为限定变量作用域范围的方式。

点评

嗯,嵌套函数在变量共享方面确实很方便  发表于 2013-9-18 02:09

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2013-9-17 16:41:15 | 显示全部楼层 来自 英国
对于lz的两个论述,我的理解是这样的:
有关嵌套函数的输入、输出参数,在大多数情况下是对的,也就是说嵌套函数不需要输入、输出参数,但是有一种情况你可能需要,那就是如果该父函数把指向该嵌套函数的句柄返回给调用函数,这种情况下你可能需要额外的输入参数,请参见matlab文档关于嵌套函数的makeParabola例子。

另外,可能和编程习惯有关,有些人可能倾向于给嵌套函数设定输入、输出参数,这样有利于明确变量的作用域。清晰的变量作用域范围有助于维护大型程序。

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2013-9-17 17:01:05 | 显示全部楼层 来自 河北廊坊
我觉得嵌套函数给变量共享提供了一种方式,至于输入变量和输出变量是否要设定,要根据具体的情况而定,如果该变量在嵌套函数外部需要使用的话,那就不必设为输入或者输出变量,让其共享便可以,如果该变量只在嵌套函数内部使用的话,那就没有必要共享,而作为输入变量或者输出变量

ls关于外部函数调用子函数的时候,需要用句柄传递的例子,是不是和lz所说的情况不一致?lz说的是内嵌的函数是否需要设置输入和输出,ls说的是父函数需要设置输入和输出吧

不知道我的理解是否正确,希望指正

点评

嗯,我跟你的理解相同  发表于 2013-9-18 03:01

评分

1

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2013-9-18 02:47:48 | 显示全部楼层 来自 加拿大
本帖最后由 winner245 于 2013-9-18 03:08 编辑
taohe 发表于 2013-9-17 16:41
对于lz的两个论述,我的理解是这样的:
有关嵌套函数的输入、输出参数,在大多数情况下是对的,也就是说嵌 ...

我查阅了一下你提到的这个例子。函数定义是:
  1. function countfcn = makecounter(initvalue)
  2. %MAKECOUNTER Used by NESTEDDEMO.
  3. % This function returns a handle to a customized nested function 'getCounter'.
  4. % initvalue specifies the initial value of the counter whose's handle is returned.

  5. % Copyright 1984-2004 The MathWorks, Inc.
  6. % $Revision: 1.1.6.2 $  $Date: 2004/03/02 21:46:55 $

  7. currentCount = initvalue; % Initial value
  8. countfcn = @getCounter;   % Return handle to getCounter

  9.     function count = getCounter
  10.         % This function increments the variable 'currentCount', when it
  11.         % gets called (using its function handle) .
  12.         currentCount = currentCount + 1;
  13.         count = currentCount;
  14.     end
  15. end
复制代码
你说的是 makecounter 函数要返回其内部嵌套函数 getCounter 的函数句柄 @getCounter 吧?假如 makecounter 函数只是想把 @getCounter 返回给其上层函数的话,即使这里 makecounter 函数定义没有返回值 countfcn,我觉得也是没有问题的,只要 makecounter 函数定义里有 countfcn = @getCounter; 这一句,这样,得到的变量 countfcn 就可以被其(直系)上层函数共享。比如,下面的例子里我将不带返回值的makecounter函数(去掉多余的help信息)嵌套在主函数main里,我让main调用makecounter后,看我能否得到getCounter 的函数句柄 :
  1. function main
  2.     clear all
  3.     close all
  4.     clc
  5.     makecounter(1);
  6.     countfcn
  7.     function makecounter(initvalue)       % 注意:此处 makecounter 函数定义并没有返回值
  8.         currentCount = initvalue; % Initial value
  9.         countfcn = @getCounter; % Return handle to getCounter
  10.         
  11.         function count = getCounter
  12.             currentCount = currentCount + 1;
  13.             count = currentCount;
  14.         end
  15.     end
  16. end
复制代码
运行后结果为:
countfcn =

    @main/makecounter/getCounter

说明即使 makecounter 函数不带返回值,它可以向其父函数 main 返回其嵌套函数getCounter的函数句柄。


还有一种情况是:函数 M 并非是 makecounter 直系父函数(main),而是 main 的一个兄弟函数,即 M 和 main 都被嵌套在一个共同的函数 C 里 (这里的直系和兄弟的说法参考自吴兄的书)。很显然,M 是可以调用 makecounter 的,但是并不能与 makecounter 共享变量。尽管如此,M 也可以通过父函数 C 间接地访问 makecounter 里的变量,进而访问makecounter 的嵌套函数getCounter。做法是,C 在调用 M 之前,先调用了 main,main 里又调用了 makecounter,makecounter 里获取了函数句柄 @getCounter。所以,最终 @getCounter 可以被传回 C 里。此时,C 再调用 M,M即可自由从 C 里获取 @getCounter 了。即 @getCounter 了 经历了 从 makecounter -----> main -----> C -----> M 的传递。这个调用如下:
  1. function C
  2.     clear all
  3.     close all
  4.     clc
  5.     main;
  6.     M;
  7.     countfcn;
  8.     function main
  9.         makecounter(1);
  10.         countfcn;
  11.         function makecounter(initvalue)
  12.             currentCount = initvalue; % Initial value
  13.             countfcn = @getCounter; % Return handle to getCounter

  14.             function count = getCounter
  15.                 currentCount = currentCount + 1;
  16.                 count = currentCount;
  17.             end
  18.         end
  19.     end

  20.     function M
  21.         countfcn
  22.     end
  23. end
复制代码
结果是

countfcn =

    @C/main/makecounter/getCounter

回复 不支持

使用道具 举报

发表于 2013-9-18 05:04:05 | 显示全部楼层 来自 英国
我提到的是关于嵌套函数的文档中的makeParabola例子,下面是链接:

_http://www.mathworks.co.uk/help/ ... sted-functions.html
回复 不支持

使用道具 举报

 楼主| 发表于 2013-9-18 09:49:15 | 显示全部楼层 来自 加拿大
taohe 发表于 2013-9-18 05:04
我提到的是关于嵌套函数的文档中的makeParabola例子,下面是链接:

_http://www.mathworks.co.uk/help/mat ...

嗯,不好意思,我找错了例子。我刚看了一下 makeParabola 的例子,这个例子里虽然需要嵌套函数返回的函数句柄,同时父函数向嵌套函数提供输入参数,但是,实际上,这些函数返回值和输入参数也都可以避免,只要按照嵌套函数变量共享的原则,通过我楼上描述的逐层调用的办法,也可以在没有任何函数参数和返回值的情况下等效实现makeParabola 的功能。

首先,先说一下原始的 makeParabola 的例子,我都将 makeParabola 放在主函数 main 里考虑,这样无需在command window里输入调用了。

1. 原始的 makeParabola 例子
  1. function main
  2.     p = makeParabola(1.3,.2,30);

  3.     x = [-25,25];
  4.     Y = p(x)

  5.     function p = makeParabola(a,b,c)
  6.        p = @parabola;

  7.        function y = parabola(x)
  8.        y = a*x.^2 + b*x + c;
  9.        end

  10.     end
  11. end
复制代码
结果为:

Y =

  837.5000  847.5000


2. 去掉上面原始例子里的嵌套函数返回值和参数后的实现方法
  1. function main
  2.     a = 1.3; b = 0.2; c = 30; x = [-25,25];
  3.     makeParabola;  
  4.     Y = y1

  5.     function makeParabola
  6.         parabola;
  7.         y1 = y;
  8.         
  9.         function parabola
  10.             y = a*x.^2 + b*x + c;
  11.         end
  12.         
  13.     end
  14. end
复制代码
结果为:
Y =

  837.5000  847.5000


可以看到,第2种方法既无输入参数,也无函数返回值,但却实现了第1种方法一样的功能。只不过,不得不承认的是,对于这类需要返回函数句柄,并且期望给嵌套函数函数参数的情形,还是有参数和返回值更容易实现。因为第2种方法为了共享变量,只能通过父函数逐层调用实现

点评

嵌套函数优势还是很明显的,变量共享,比如在写GUI回调函数的时候  发表于 2013-9-18 14:33
个人感觉nested 函数并没有太多的优势,主函数调用子函数的变量需要逐层,子函数可以随意access主函数变量,还不如普通函数更为快捷和易于维护  发表于 2013-9-18 13:56

评分

2

查看全部评分

回复 不支持

使用道具 举报

发表于 2013-9-18 11:07:50 | 显示全部楼层 来自 河北廊坊
在亨塞尔曼的书中这样写道:函数句柄的另一个重要特性是它们可以用来标识子函数,私有函数和嵌套函数,一般情况下,这些函数对于用户来说是“隐藏”的,这些标识对于用户正确使用这些函数非常有用。
个人认为:在这样用法中,最好给嵌套函数带上必要的输入参数和输出参数,为了避免不用输入参数和输出参数,而带来一些复杂的操作,就没有必要了。
当然,lz的题目很明确,是否存在必须使用输入和输出参数的例子。
这个问题要看你怎么理解:如果要利用函数句柄来标识嵌套函数,那么就必要带输入和输出参数,就像taohe兄给出的例子一样,虽然lz给出一个不带参数的例子,但是这个例子没有将嵌套函数标识出来到基本的空间中,不能被其他函数调用,而是标识到了另外一个函数文件中
以上仅仅是个人的理解,希望指正

点评

nested function在GUI中做callback的例子未见各种地方详细谈及,也许后续版本的demo中有,但没有看过。哪位闲暇能编一个就好了。  发表于 2013-9-18 16:20

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2013-9-18 16:41:00 | 显示全部楼层 来自 河北廊坊
我根据自己的理解,给出一个例子吧,原来的程序来自网络,嵌套的是自己修改的
不用嵌套函数的例子

  1. function [] = GUI_16()
  2. % Demonstrate display & change a slider's position & limits with edit boxes  
  3. % This is an extension of GUI_13. Slide the slider and it's position will
  4. % be shown in the editbox.  Enter a valid number in the editbox and the
  5. % slider will be moved to that position.  If the number entered is outside
  6. % the range of the slider, the number will be reset.  The range of the
  7. % slider will be shown in two editboxes on either side of the slider.  The
  8. % user may change the range of the slider, as long as valid entries are
  9. % made.
  10. %
  11. % Suggested exercise:  Notice that any number (>min) is acceptable for the
  12. % max range number, and that when max is chosen such that max < value,
  13. % value is set equal to max.  Modify the code to restrict max>=value.  Do
  14. % similarly for the min.
  15. %
  16. %
  17. % Author:  Matt Fig
  18. % Date:  7/15/2009

  19. S.fh = figure('units','pixels',...
  20.               'position',[300 300 390 100],...
  21.               'menubar','none',...
  22.               'name','GUI_16',...
  23.               'numbertitle','off',...
  24.               'resize','off');
  25. S.sl = uicontrol('style','slide',...
  26.                  'unit','pix',...
  27.                  'position',[60 10 270 30],...
  28.                  'min',1,'max',100,'val',50);
  29. S.ed(1) = uicontrol('style','edit',...
  30.                     'unit','pix',...
  31.                     'position',[10 10 40 30],...
  32.                     'fontsize',12,...
  33.                     'string','1');   % Displays the min.         
  34. S.ed(2) = uicontrol('style','edit',...
  35.                     'unit','pix',...
  36.                     'position',[60 50 270 30],...
  37.                     'fontsize',16,...
  38.                     'string','50');  % Displays the value.
  39. S.ed(3) = uicontrol('style','edit',...
  40.                     'unit','pix',...
  41.                     'position',[340 10 40 30],...
  42.                     'fontsize',12,...
  43.                     'string','100');    % Displays the max.   
  44. set([S.ed(:);S.sl],'call',{@sl_call,S});  % Shared Callback.



  45. function [] = sl_call(varargin)
  46. % Callback for the edit box and slider.
  47. [h,S] = varargin{[1,3]};  % Get calling handle and structure.
  48. SL = get(S.sl,{'min','value','max'});  % Get the slider's info.
  49. E = str2double(get(h,'string'));  % Numerical edit string.

  50. switch h  % Who called?
  51.     case S.ed(1)
  52.         if E <= SL{2}
  53.             set(S.sl,'min',E)  % E is less than current value.
  54.         elseif E < SL{3}
  55.             set(S.sl,'val',E,'min',E) % E is less than max value.
  56.             set(S.ed(2),'string',E) % Set the current display.
  57.         else
  58.             set(h,'string',SL{1}) % Reset the value.
  59.         end
  60.     case S.ed(2)
  61.         if E >= SL{1} && E <= SL{3}
  62.             set(S.sl,'value',E)  % E falls within range of slider.
  63.         else
  64.             set(h,'string',SL{2}) % User tried to set slider out of range.
  65.         end
  66.     case S.ed(3)
  67.         if E >= SL{2}
  68.             set(S.sl,'max',E)  % E is less than current value.
  69.         elseif E > SL{1}
  70.             set(S.sl,'val',E,'max',E) % E is less than max value.
  71.             set(S.ed(2),'string',E) % Set the current display.
  72.         else
  73.             set(h,'string',SL{3}) % Reset the value.
  74.         end      
  75.     case S.sl
  76.         set(S.ed(2),'string',SL{2}) % Set edit to current slider.
  77.     otherwise
  78.         % Do nothing
  79. end




复制代码
用嵌套函数的例子
  1. function [] = GUI_16()
  2. % Demonstrate display & change a slider's position & limits with edit boxes
  3. % This is an extension of GUI_13. Slide the slider and it's position will
  4. % be shown in the editbox.  Enter a valid number in the editbox and the
  5. % slider will be moved to that position.  If the number entered is outside
  6. % the range of the slider, the number will be reset.  The range of the
  7. % slider will be shown in two editboxes on either side of the slider.  The
  8. % user may change the range of the slider, as long as valid entries are
  9. % made.
  10. %
  11. % Suggested exercise:  Notice that any number (>min) is acceptable for the
  12. % max range number, and that when max is chosen such that max < value,
  13. % value is set equal to max.  Modify the code to restrict max>=value.  Do
  14. % similarly for the min.
  15. %
  16. %
  17. % Author:  Matt Fig
  18. % Date:  7/15/2009

  19. S.fh = figure('units','pixels',...
  20.     'position',[300 300 390 100],...
  21.     'menubar','none',...
  22.     'name','GUI_16',...
  23.     'numbertitle','off',...
  24.     'resize','off');
  25. S.sl = uicontrol('style','slide',...
  26.     'unit','pix',...
  27.     'position',[60 10 270 30],...
  28.     'min',1,'max',100,'val',50);
  29. S.ed(1) = uicontrol('style','edit',...
  30.     'unit','pix',...
  31.     'position',[10 10 40 30],...
  32.     'fontsize',12,...
  33.     'string','1');   % Displays the min.
  34. S.ed(2) = uicontrol('style','edit',...
  35.     'unit','pix',...
  36.     'position',[60 50 270 30],...
  37.     'fontsize',16,...
  38.     'string','50');  % Displays the value.
  39. S.ed(3) = uicontrol('style','edit',...
  40.     'unit','pix',...
  41.     'position',[340 10 40 30],...
  42.     'fontsize',12,...
  43.     'string','100');    % Displays the max.
  44. set([S.ed(:);S.sl],'call',@sl_call);  % Shared Callback.

  45.     function [] = sl_call(h,~)
  46.         % Callback for the edit box and slider.
  47. %         [h,S] = varargin{[1,3]};  % Get calling handle and structure.
  48.         SL = get(S.sl,{'min','value','max'});  % Get the slider's info.
  49.         E = str2double(get(h,'string'));  % Numerical edit string.
  50.         
  51.         switch h  % Who called?
  52.             case S.ed(1)
  53.                 if E <= SL{2}
  54.                     set(S.sl,'min',E)  % E is less than current value.
  55.                 elseif E < SL{3}
  56.                     set(S.sl,'val',E,'min',E) % E is less than max value.
  57.                     set(S.ed(2),'string',E) % Set the current display.
  58.                 else
  59.                     set(h,'string',SL{1}) % Reset the value.
  60.                 end
  61.             case S.ed(2)
  62.                 if E >= SL{1} && E <= SL{3}
  63.                     set(S.sl,'value',E)  % E falls within range of slider.
  64.                 else
  65.                     set(h,'string',SL{2}) % User tried to set slider out of range.
  66.                 end
  67.             case S.ed(3)
  68.                 if E >= SL{2}
  69.                     set(S.sl,'max',E)  % E is less than current value.
  70.                 elseif E > SL{1}
  71.                     set(S.sl,'val',E,'max',E) % E is less than max value.
  72.                     set(S.ed(2),'string',E) % Set the current display.
  73.                 else
  74.                     set(h,'string',SL{3}) % Reset the value.
  75.                 end
  76.             case S.sl
  77.                 set(S.ed(2),'string',SL{2}) % Set edit to current slider.
  78.             otherwise
  79.                 % Do nothing
  80.         end
  81.     end
  82. end



复制代码

评分

1

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2013-9-18 20:12:14 | 显示全部楼层 来自 加拿大
qibbxxt 发表于 2013-9-18 11:07
在亨塞尔曼的书中这样写道:函数句柄的另一个重要特性是它们可以用来标识子函数,私有函数和嵌套函数,一般 ...

嗯,同意你的看法 ”为了避免不用输入参数和输出参数,而带来一些复杂的操作,就没有必要了“。确实,如我上面的例子,一味地利用共享变量确实可以避免参数和返回值,却让嵌套函数使用变得更麻烦了,这个是不可取的。实际中,应该根据情况,灵活决定是使用共享变量还是使用参数和返回值
回复 不支持

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-6-21 00:59 , Processed in 0.053468 second(s), 20 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表