4.6 函数的类型
在4.5.4小节中的示例文件playnoisef5.m中,包含两个函数:一个是playnoisef5,一个是getmyParameter。前者与M文件的名称相同,称为主函数,后者称为子函数。除此之外,还有私有函数和嵌套函数以及匿名函数,此处主要讲主函数和子函数。
4.6.1 主函数
MATLAB 程序文件(M 文件)中的第一个函数称为主函数,大多数情况下主函数是程序文件中的唯一函数,即如果一个程序文件中只包括一个函数,则该函数就是主函数。在前面的示例文件中, playnoisef.m~playnoisef3.m文中的函数是唯一的,都是主函数。在playnoisef4.m和playnoisef5.m中,排在最前面的函数是主函数,即相应的playnoisef4和playnoisef5。一般而言,主函数与M文件的名称相同,如果不相同,只能使用文件名来调用函数,而不是关键字function后面所起的函数名。
4.6.2 子函数
所谓子函数,是因其无法单独定义,在主函数所在的程序文件中进行定义,且一个程序中可以定义多个子函数,子函数只能供同一程序文件中的主函数或其他子函数调用,而不能被其他程序文件中的主函数或子函数调用,这也是常常将一个函数存储为一个程序文件,即定义为主函数的原因,这样不同的函数之间就可以方便地调用。
4.6.3 函数间的调用关系
尽管有主函数和子函数之分,由于 MATLAB 语言支持递归,故主函数和子函数间的调用关系并没有限制,即主函数可以调用子函数,子函数也可以调用主函数,主函数仅仅是因其排在程序文件中的第一个。看下面的程序示例,函数afunction中调用bfunction,bfunction函数中调用cfunction,函数cfunction中又调用afunction,三个函数循环调用(但一般不要将程序设计成循环调用)。
文件名:afunction.m(文件位于Psyfeng\Little_Examples目录下)
function afunction() %定义函数afunction global var if isempty(var) var=1; else var=var+1; end if var<100 disp(['In function a:' num2str(var)]); %如果变量var值小于100,则显示信息bfunction; %调用函数bfunction end end function bfunction() global var if isempty(var) var=1; else var=var+1; end if var<100 disp(['In function b:' num2str(var)]); cfunction; %调用函数cfunction end end function cfunction() global var if isempty(var) var=1; else var=var+1; end if var<100 disp(['In function c:' num2str(var)]); afunction; %调用函数afunction end end
运行以上程序,输出结果如下:
>> clear all↙ >> afunction↙
In function a:1 In function b:2 In function c:3 In function a:4 In function b:5 In function c:6 ┇ ┇ In function a:97 In function b:98 In function c:99
以上三个函数因为afunction排在第一个,所以M文件名为afunction.m,即使将程序的文件名改为bfunction.m,也无法使第二个函数成为主函数,此时在命令窗口中输入afunction,会出现如下提示信息(未找到函数)。
>> afunction↙
??? Undefined function or variable 'afunction'.
改变文件的名称后,如果文件名与主函数名不符,就需要使用文件名来调用函数,但由于函数afunction排在第一位,所以当输入bfunction(文件名)时,会调用afunction函数,而非文件中定义的子函数bfunction,下面验证一下。
>> clear all↙ >>bfunction↙
In function a:1 In function a:2 In function a:3 In function a:4 In function a:5 In function a:6 ┇ ┇ In function a:97 In function a:98 In function a:99
从输出结果可以看出,改名后输入bfunction会始终调用afunction主函数,尽管在afunction中调用了bfunction,但由于“bfunction”作为了函数afunction的文件名,所以相当于自己调用自己,这也是 MATLAB 的强大之处,其他编程语言一般无法实现自己调用自己。例如,下面的程序可以将某个目录下的所有目录(包含子目录)列出。
文件名:listdir.m(文件位于Psyfeng\Little_Examples目录下)
function listdir(directory) if nargin<1 directory='..'; end s=dir(directory); %获取目录directory下内容 for i=1:length(s) if s(i).isdir && ~strcmp(s(i).name,'.') && ~strcmp(s(i).name,'..') disp(fullfile(directory,s(i).name)); %显示全路径名 listdir(fullfile(directory,s(i).name)); %如果是目录,则循环调用listdir函数 end end end
运行示例如下。
>> listdir('c:\')↙
c:\DRIVERS c:\DRIVERS\WIN c:\DRIVERS\WIN\4IN1 c:\DRIVERS\WIN\4IN1\MS c:\DRIVERS\WIN\4IN1\MSx64 c:\DRIVERS\WIN\4IN1\SDMMC c:\DRIVERS\WIN\4IN1\SDMMCx64 c:\DRIVERS\WIN\4IN1\XD c:\DRIVERS\WIN\4IN1\xDx64 c:\DRIVERS\WIN\AMTSOL ┇ ┇
4.6.4 函数的调用顺序
如果不小心定义了与 MATLAB 系统内置函数相同的函数,在调用函数时,到底使用的是哪个函数呢?MATLAB 在查找函数时使用以下规则,首先在当前目录下查找函数,如果没有找到,则按照MATLAB路径中设置的先后顺序(通过path命令可以列出当前的路径设置情况),所以如果程序没有在当前目录下,并且程序所在的目录也没有加入 MATLAB 路径中,就会出现错误信息(即无法找到指定的函数)。因此,为了确保函数能够顺利运行,一种方式是切换程序所在目录为当前目录,另一种方式是将程序所在目录添加到MATLAB路径中(参见5.6节)。
可以利用which函数明确到底是哪个函数被调用,以及被调用文件所在的目录。