PSYCHTOOLBOX工具箱及MATLAB编程实例
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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函数明确到底是哪个函数被调用,以及被调用文件所在的目录。