是否可以在MATLAB中为每个文件定义一个以上的函数,然后从该文件外部访问它们?


216

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

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

如果可以在一个文件中放置多个功能,是否对此有任何限制?例如,可以从文件外部访问文件中的所有功能,还是仅从名称相同的功能访问文件?

注意:我正在使用MATLAB版本R2007b。

Answers:


270

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

m文件中的所有后续函数(称为本地函数(或旧术语中的“子函数”))只能由该m文件中的main函数和其他本地函数调用。其他m文件中的函数无法调用它们。从R2016b开始,您还可以向脚本中添加本地函数,尽管作用域范围仍然相同(即只能在脚本中调用它们)。

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

更多值得深思的...

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

例如,假设你有一个主要功能A在m文件A.m,与当地职能一起DEF。现在让我们假设你有两个其他相关功能B,并C在M文件B.mC.m分别,你也希望能够呼吁DEF。这里有一些选项:

  • DEF分别放在各自独立的m文件中,以允许其他任何函数调用它们。缺点是,这些功能的范围很广,并不仅仅限于ABC,但上涨空间,这是非常简单的。

  • 创建defineMyFunctions(在Jonas的例子等)m文件用DEF作为本地函数和一个主功能,简单地返回函数处理它们。这样,您就可以将DE和保留F在同一文件中,但是对于这些函数的作用域则不做任何事情,因为任何defineMyFunctions可以调用的函数都可以调用它们。然后,您还必须担心将函数句柄作为参数传递,以确保将它们放在需要的位置。

  • 复制DEF进入B.mC.m本地功能。这限制了它们的使用,只是范围ABC,反而使得更新和你的代码是一场噩梦的维护,因为你必须在不同的地方相同的代码的三个副本。

  • 使用私有功能如果你有AB以及C在同一目录下,你可以创建一个名为的子目录private和地点DE以及F在那里,每一个都是独立的m文件。这限制了它们的范围,使他们只能通过功能,在目录正上方叫(即ABC),并在同一个地方让他们在一起(但仍不同的m文件):

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

所有这些都超出了您的问题范围,并且可能比您需要的细节更多,但是我认为最好涉及组织所有m文件的更普遍的关注。;)


3
最喜欢的答案选项如下所示^:@idigas
嵌入

1
@embert我认为他的意思是赞成一个问题,可以独立于赞成而进行投票。
OJFord 2015年

78

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

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

36

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

自R2008a以来,才正式支持OOP功能,因此,除非您要使用未记录的旧OOP语法,否则答案为否,如@gnovice所述

编辑

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


我不会为此目的使用oop,它会增加大量的开销,尤其是对于静态方法。(stackoverflow.com/questions/1693429/…)–
丹尼尔

1
@Daniel:仅当您执行大量的函数调用并且该方法中的计算是准瞬时的时,开销才是明显的。两种情况通常都指向错误的设计-没有矢量化和无意义的功能。因此,我不会太担心。
乔纳斯(Jonas)2015年

23

我真的很喜欢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

assignin('caller',...)会更正确。您可能想从另一个功能中使用这些功能。
克里斯·伦戈

10

与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);     

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'.

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')


0

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

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

但是,其他答案中建议的解决方法也可以达到类似目的。


这不是格诺维采在回答开始时所说的吗?
阿迪尔

@Adiel也许,但是自从回答以来已经过去了几年了,有人可能想知道是否有任何变化。
Dev-iL

如果有什么变化,我还是没得到...?:)
阿迪尔

不。除了可能添加了一些文档来解决该特定主题之外。
Dev-iL

我之所以写这个答案,是因为几个版本之前,他们引入了可以添加到脚本末尾的函数 -因此人们可能想知道这方面是否也有所变化(答案:否)。
Dev-iL

-1

我尝试使用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 都不对我起作用八度。我写的那本书很完美(我上周五在后来写这篇文章时对其进行了测试)。


2
如果您可以解释这与您要复制的两个现有答案有何不同,我将删除我的不赞成投票。抱歉,您没有对此发表评论。我只是没有看到这有什么不同,除了您将这两种方法都组合到一个函数中,因此做了一些多余的事情。另外,请插入指向您所引用答案的正确链接,“ + 72”和“ +20”非常含糊,我花了一段时间才意识到您所引用的投票数会随着时间的变化而变化,并成为您的引用难以理解。
克里斯·伦戈
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.