225

当我攻读 EE 本科学位时,MATLAB 要求每个函数都在自己的文件中定义,即使它是单行的。

我现在正在攻读研究生学位,我必须在 MATLAB 中编写一个项目。这仍然是较新版本的 MATLAB 的要求吗?

如果可以在一个文件中放置多个函数,是否有任何限制?例如,可以从文件外部访问文件中的所有函数,还是只访问与文件同名的函数?

注意:我使用的是 MATLAB 版本 R2007b。

4

9 回答 9

278

m 文件中的第一个函数(即main 函数)在调用该 m 文件时被调用。不要求主函数与 m 文件具有相同的名称,但为了清楚起见,它应该. 当函数和文件名不同时,必须使用文件名来调用主函数。

m 文件中的所有后续函数,称为局部函数(或旧术语中的“子函数”),只能由该 m 文件中的主函数和其他局部函数调用。其他 m 文件中的函数不能调用它们。从 R2016b 开始,您也可以将本地函数添加到脚本中,尽管作用域行为仍然相同(即它们只能从脚本中调用)。

此外,您还可以其他函数中声明函数。这些被称为嵌套函数,并且只能从它们嵌套的函数中调用。它们还可以访问嵌套它们的函数中的变量,这使得它们非常有用,尽管使用起来有些棘手。

更多值得深思...

有一些方法可以绕过上面概述的正常函数范围行为,例如将函数句柄作为输出参数传递,如SCFrenchJonas的答案中提到的(从 R2013b 开始,函数促进了这一点localfunctions)。但是,我不建议养成使用这些技巧的习惯,因为组织函数和文件可能有更好的选择。

例如,假设您A在 m-file 中有一个 main 函数A.m,以及本地函数DEF。现在假设您有另外两个相关函数B,并且分别C在 m-filesB.mC.m中,您还希望能够调用DEF。以下是您的一些选择:

  • DEF各自放在各自单独的 m 文件中,允许任何其他函数调用它们。缺点是这些函数的范围很大并且不仅限于ABC,但优点是这很简单。

  • 创建一个defineMyFunctionsm 文件(如在 Jonas 的示例中),其中D, E, 和F作为本地函数和一个简单地向它们返回函数句柄的 main 函数。这允许您将DE和保留F在同一个文件中,但它不会对这些函数的范围做任何事情,因为任何可以调用的函数都defineMyFunctions可以调用它们。然后,您还必须担心将函数句柄作为参数传递,以确保将它们放在需要的地方。

  • 复制D,EFintoB.mC.m作为本地函数。这将它们的使用范围限制为ABC,但会使代码的更新和维护成为一场噩梦,因为您在不同的地方拥有相同代码的三个副本。

  • 使用私有函数如果您有A, B, 和C在同一个目录中,您可以创建一个名为的子目录private,并将D,EF放在其中,每个都作为一个单独的 m 文件。这限制了它们的范围,因此它们只能被上面目录中的函数调用(即ABC),并将它们放在同一个地方(但仍然是不同的 m 文件):

    myDirectory/
        A.m
        B.m
        C.m
        private/
            D.m
            E.m
            F.m
    

所有这些都超出了您的问题范围,并且可能比您需要的更详细,但我认为触及组织所有 m 文件的更普遍问题可能会很好。;)

于 2010-08-25T20:28:24.767 回答
81

通常,您的问题的答案是否定的,您不能为每个文件定义多个外部可见函数。但是,您可以将函数句柄返回给本地函数,并且一种方便的方法是使它们成为结构的字段。这是一个例子:

function funs = makefuns
  funs.fun1=@fun1;
  funs.fun2=@fun2;
end

function y=fun1(x)
  y=x;
end

function z=fun2
  z=1;
end

以下是它的使用方法:

>> myfuns = makefuns;
>> myfuns.fun1(5)    
ans =
     5
>> myfuns.fun2()     
ans =
     1
于 2010-08-26T01:15:12.287 回答
38

在单个文件中拥有多个可单独访问的函数的唯一方法是使用面向对象编程定义静态方法。您将访问该功能,等等。myClass.static1()myClass.static2()

自 R2008a 起才正式支持 OOP 功能,因此除非您想使用旧的、未记录的 OOP 语法,否则您的答案是否定的,正如@gnovice所解释的那样。

编辑

在文件中定义可从外部访问的多个函数的另一种方法是创建一个返回多个函数句柄的函数。换句话说,您将定义函数称为[fun1,fun2,fun3]=defineMyFunctions,之后您可以使用out1=fun1(inputs)等。

于 2010-08-25T20:37:33.227 回答
24

我真的很喜欢 SCFrench 的回答——我想指出,它可以很容易地修改为使用 assignin 函数将函数直接导入工作区。(这样做让我想起了很多 Python 的“从 y 导入 x”的做事方式)

function message = makefuns
  assignin('base','fun1',@fun1);
  assignin('base','fun2',@fun2);
  message='Done importing functions to workspace';
end

function y=fun1(x)
  y=x;
end

function z=fun2
  z=1;
end

然后如此使用:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
于 2013-06-01T06:59:54.213 回答
12

与 SCFrench 的答案相同,但具有更多 C# 风格的旋转..

我会(并且经常这样做)创建一个包含多个静态方法的类。例如:

classdef Statistics

    methods(Static)
        function val = MyMean(data)
            val = mean(data);
        end

        function val = MyStd(data)
            val = std(data);
        end
    end

end

由于方法是静态的,因此您不需要实例化该类。您可以按如下方式调用函数:

data = 1:10;

mean = Statistics.MyMean(data);
std = Statistics.MyStd(data);     
于 2014-07-31T09:35:53.840 回答
4

我使用 Octave 在一个 .m 文件中定义了多个函数,然后在需要使用该文件中的函数的 .m 文件中使用命令:

source("mycode.m");

不确定这是否适用于 Matlab。

octave:8> help source
'source' is a built-in function

 -- Built-in Function:  source (FILE)
     Parse and execute the contents of FILE.  This is equivalent to
     executing commands from a script file, but without requiring the
     file to be named `FILE.m'.
于 2013-07-13T01:14:45.347 回答
3

您还可以将函数组合在一个主文件中,主函数如下所示:

function [varargout] = main( subfun, varargin )
[varargout{1:nargout}] = feval( subfun, varargin{:} ); 

% paste your subfunctions below ....
function str=subfun1
str='hello'

然后调用subfun1将如下所示: str=main('subfun1')

于 2013-06-03T18:46:20.833 回答
0

从 R2017b 开始,这在官方上是不可能的。相关文件指出:

程序文件可以包含多个功能。如果文件仅包含函数定义,则第一个函数是主函数,并且是 MATLAB 与文件名关联的函数。跟在主函数或脚本代码后面的函数称为局部函数。本地函数仅在文件中可用。

但是,其他答案中建议的解决方法可以实现类似的效果。

于 2017-10-23T10:19:48.727 回答
-2

我尝试过使用SCFRench和使用八度音阶的Ru Hasha

最后它起作用了: 但我做了一些修改

function message = makefuns
    assignin('base','fun1', @fun1);   % Ru Hasha
    assignin('base', 'fun2', @fun2);  % Ru Hasha
    message.fun1=@fun1;               % SCFrench
    message.fun2=@fun2;               % SCFrench
end

function y=fun1(x)
    y=x;
end

function z=fun2
    z=1;
end

可以在其他'm'文件中调用:

printf("%d\n", makefuns.fun1(123));
printf("%d\n", makefuns.fun2());

更新:

我添加了一个答案,因为+72和 +20 对我来说都不是度音阶。我写的那个很完美(我上周五写这篇文章时测试了它)。

于 2018-11-23T15:09:39.617 回答