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

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

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

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

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

Ответы [ 9 ]

262 голосов
/ 26 августа 2010

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

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

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

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

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

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

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

  • Создайте defineMyFunctions m-файл (как в примере с 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, каждый в виде отдельного m-файла. Это ограничивает их область действия, поэтому они могут вызываться только функциями из каталога, расположенного непосредственно выше (т. Е. A, B и C), и хранят их вместе в одном месте (но все же в разных m-файлах):

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

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

75 голосов
/ 26 августа 2010

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

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 голосов
/ 26 августа 2010

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

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

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

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

23 голосов
/ 01 июня 2013

Мне очень нравится ответ 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
8 голосов
/ 31 июля 2014

По тем же строкам, что и ответ 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 голосов
/ 13 июля 2013

Я определяю несколько функций в одном файле .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'.
3 голосов
/ 03 июня 2013

Вы также можете сгруппировать функции в один основной файл вместе с основной функцией, которая выглядит следующим образом:

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

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

Тогда вызов subfun1 будет выглядеть так: ул = основная ( 'subfun1')

0 голосов
/ 23 ноября 2018

У меня есть попытка с 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());

update:

Я добавил ответ, потому что ни +72, ни +20 не работали в октаве для меня.Тот, который я написал, отлично работает (и я протестировал его в прошлую пятницу, когда позже написал пост).

0 голосов
/ 23 октября 2017

Начиная с R2017b, это официально невозможно.В соответствующей документации указано, что:

Программные файлы могут содержать несколько функций.Если файл содержит только определения функций, первая функция - это основная функция, и это функция, которую MATLAB связывает с именем файла.Функции, которые следуют за основной функцией или кодом скрипта, называются локальными функциями.Локальные функции доступны только внутри файла.

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

...