Можно ли определить более одной функции для файла в MATLAB и получить к ним доступ вне этого файла?

217

Когда я учился на степень бакалавра в EE, MATLAB требовал, чтобы каждая функция была определена в своем собственном файле, даже если она была однострочной.

Сейчас я учусь в аспирантуре, и мне нужно написать проект в MATLAB. Требуется ли это для более новых версий MATLAB?

Если в файл можно поместить более одной функции, есть ли ограничения? Например, можно ли получить доступ ко всем функциям в файле извне файла или только к функции, имя которой совпадает с именем файла?

Примечание: я использую версию MATLAB R2007b.

Натан Феллман
источник

Ответы:

271

Первая функция в m-файле (то есть основная функция ) вызывается при вызове этого m-файла. Не обязательно , чтобы основная функция имела то же имя, что и m-файл, но для ясности она должна . Когда функция и имя файла различаются, имя файла должно использоваться для вызова основной функции.

Все последующие функции в m-файле, называемые локальными функциями (или «подфункциями» в более старой терминологии), могут вызываться только основной функцией и другими локальными функциями в этом m-файле. Функции в других m-файлах не могут вызывать их. Начиная с R2016b, вы также можете добавлять локальные функции в сценарии , хотя поведение области действия остается прежним (то есть их можно вызывать только из сценария).

Кроме того, вы также можете объявить функции в других функциях. Они называются вложенными функциями и могут вызываться только из той функции, в которую они вложены. Они также могут иметь доступ к переменным в функциях, в которые они вложены, что делает их весьма полезными, хотя и немного сложными для работы.

Больше пищи для размышлений ...

Есть несколько способов , вокруг нормального поведения функции обзорного , описанных выше, такие как прохождение функции ручки в качестве выходных аргументов , как указано в ответах от SCFrench и Джонаса (который, начиная с R2013b, облегчаются с помощью localfunctionsфункции). Однако я бы не советовал прибегать к таким уловкам, так как, вероятно, есть гораздо лучшие варианты для организации ваших функций и файлов.

Например, предположим, что у вас есть основная функция Aв м-файле A.m, наряду с локальными функциями D, Eи F. Теперь предположим, что у вас есть два других связанных с ними функций Bи Cв м-файлов B.mи C.m, соответственно, что вы хотите быть в состоянии назвать D, Eи F. Вот несколько вариантов, которые у вас есть:

  • Положите D, Eи Fкаждый в свои отдельные m-файлы, позволяя любой другой функции вызывать их. Недостатком является то, что сфера применения этих функций велик и не ограничивается только A, Bи C, но вверх, что это довольно просто.

  • Создайте defineMyFunctionsm-файл (как в примере с Jonas) с помощью D, Eи Fкак локальные функции и как главную функцию, которая просто возвращает им дескрипторы функций. Это позволяет сохранить D, Eи Fв том же файле, но это ничего не делать в отношении объема этих функций , так как любая функция , которая может вызывать defineMyFunctionsих вызова. Затем вам также придется позаботиться о передаче дескрипторов функции в качестве аргументов, чтобы убедиться, что они есть там, где они вам нужны.

  • Скопируйте D, Eи Fв B.mи C.mкак локальные функции. Это ограничивает область их использования просто A, Bи C, но делает обновление и обслуживание вашего кода кошмаром, потому что у вас есть три копии одного и того же кода в разных местах.

  • Используйте частные функции ! Если у вас есть A, Bи Cв том же каталоге, вы можете создать подкаталог privateи место D, Eи Fтам, каждый как отдельный м-файл. Это ограничивает сферу их применения , так что они могут быть вызваны только функциями в каталоге непосредственно выше (то есть A, Bи C) и держит их вместе в одном месте (но все же разные м-файлы):

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

Все это выходит за рамки вашего вопроса и, вероятно, более детально, чем вам нужно, но я подумал, что было бы неплохо затронуть более общую проблему организации всех ваших m-файлов. ;)

gnovice
источник
3
Любимый вариант ответа выглядит следующим образом ^: @idigas
embert
1
@embert Я предполагаю, что он имел в виду одобрение вопроса, за который можно проголосовать независимо от предпочтения.
OJFord
79

Как правило, ответ на ваш вопрос - нет, вы не можете определить более одной видимой снаружи функции на файл. Вы можете вернуть дескрипторы функций локальным функциям, и удобный способ сделать это - сделать их полями структуры. Вот пример:

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
SCFrench
источник
36

Единственный способ иметь несколько отдельно доступных функций в одном файле - это определять СТАТИЧЕСКИЕ МЕТОДЫ, используя объектно-ориентированное программирование . Вы бы получили доступ к функции как myClass.static1()и myClass.static2()т. Д.

Функциональность ООП официально поддерживается только начиная с R2008a, поэтому, если вы не хотите использовать старый недокументированный синтаксис ООП, ответ вам будет отрицательным, как объясняет @gnovice .

РЕДАКТИРОВАТЬ

Еще один способ определить несколько функций внутри файла, которые доступны извне, - создать функцию, которая возвращает несколько дескрипторов функций . Другими словами, вы бы назвали свою определяющую функцию как [fun1,fun2,fun3]=defineMyFunctions, после чего вы могли бы использовать out1=fun1(inputs)и т. Д.

Jonas
источник
Я бы не использовал oop для этой цели, это добавляет значительные накладные расходы, особенно для статических методов. ( stackoverflow.com/questions/1693429/… )
Даниэль
1
@Daniel: накладные расходы заметны только в том случае, если вы выполняете огромное количество вызовов функций, а вычисления в методе являются квази-мгновенными. Оба условия часто указывают на плохой дизайн - отсутствие векторизации и бессмысленные функции. Таким образом, я не был бы слишком обеспокоен.
Джонас
23

Мне очень нравится ответ SCFrench - я хотел бы отметить, что его можно легко изменить, чтобы импортировать функции непосредственно в рабочее пространство, используя функцию assignin. (Выполнение этого напоминает мне много способов Python "import x from y")

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);     
SmallJoeMan
источник
4

Я определяю несколько функций в одном файле .m с помощью Octave, а затем использую команду из файла .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'.
JD
источник
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 связывает с именем файла. Функции, которые следуют за основной функцией или кодом скрипта, называются локальными функциями. Локальные функции доступны только внутри файла.

Однако обходные пути, предложенные в других ответах, могут привести к чему-то похожему.

Dev-Ир
источник
Это не совсем то, что сказал Гновице в начале своего ответа?
Адиэль
@Adiel Возможно, но с тех пор прошло несколько лет, и кто-то может задаться вопросом, изменилось ли что-нибудь.
Dev-
Я до сих пор не получил, если что-то изменилось ...? :)
Адиэль
Нет. Помимо, возможно, какой-либо документации, которая была добавлена ​​для решения этой конкретной темы.
Dev-
Причина, по которой я написал этот ответ, заключается в том, что несколько выпусков назад они представили функции, которые вы можете добавить в конец сценариев, - поэтому можно задаться вопросом, изменилось ли что-то и в этом отношении (ответ: нет).
Dev-
-1

Я попробовал с SCFRench и с Ру Хашой на октаву.

И, наконец, это работает: но я сделал некоторые изменения

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» довольно загадочно, мне потребовалось некоторое время, чтобы понять, что вы имеете в виду подсчет голосов, который со временем изменится и сделает ваши ссылки неразборчиво.
Cris Luengo