Có thể xác định nhiều hơn một chức năng cho mỗi tệp trong MATLAB và truy cập chúng từ bên ngoài tệp đó không?


216

Khi tôi đang học văn bằng đại học về EE, MATLAB yêu cầu mỗi chức năng phải được xác định trong tệp riêng của mình, ngay cả khi đó là một lớp lót.

Bây giờ tôi đang học lấy bằng tốt nghiệp và tôi phải viết một dự án bằng MATLAB. Đây có còn là một yêu cầu cho các phiên bản mới hơn của MATLAB không?

Nếu có thể đặt nhiều hơn một chức năng trong một tệp, có bất kỳ hạn chế nào đối với việc này không? Chẳng hạn, tất cả các chức năng trong tệp có thể được truy cập từ bên ngoài tệp hay chỉ có chức năng có cùng tên với tệp?

Lưu ý: Tôi đang sử dụng MATLAB phát hành R2007b.

Câu trả lời:


270

Hàm đầu tiên trong tệp m (tức là hàm chính ), được gọi khi tệp m đó được gọi. Không yêu cầu chức năng chính có cùng tên với tập tin m, nhưng để rõ ràng thì nên . Khi chức năng và tên tệp khác nhau, tên tệp phải được sử dụng để gọi chức năng chính.

Tất cả các hàm tiếp theo trong tệp m, được gọi là hàm cục bộ (hoặc "hàm con" trong thuật ngữ cũ), chỉ có thể được gọi bởi hàm chính và các hàm cục bộ khác trong tệp m đó. Các hàm trong các tệp m khác không thể gọi chúng. Bắt đầu từ R2016b, bạn cũng có thể thêm các hàm cục bộ vào tập lệnh , mặc dù hành vi phạm vi vẫn giống nhau (nghĩa là chúng chỉ có thể được gọi từ bên trong tập lệnh).

Ngoài ra, bạn cũng có thể khai báo các hàm trong các hàm khác. Chúng được gọi là các hàm lồng nhau và chúng chỉ có thể được gọi từ bên trong hàm chúng được lồng. Họ cũng có thể có quyền truy cập vào các biến trong các hàm mà chúng được lồng vào nhau, điều này làm cho chúng khá hữu ích mặc dù hơi khó để làm việc với chúng.

Thêm thức ăn cho suy nghĩ ...

Có một số cách xung quanh hành vi phạm vi chức năng bình thường được nêu ở trên, chẳng hạn như chuyển hàm xử lý như các đối số đầu ra như được đề cập trong câu trả lời từ SCFblerJonas (bắt đầu từ R2013b, được hỗ trợ bởi localfunctionschức năng). Tuy nhiên, tôi không khuyên bạn nên tạo thói quen sử dụng các thủ thuật như vậy, vì có thể có nhiều lựa chọn tốt hơn để tổ chức các chức năng và tệp của bạn.

Ví dụ, giả sử bạn có một chức năng chính Atrong một m-file A.m, cùng với chức năng địa phương D, EF. Bây giờ giả sử bạn có hai chức năng khác có liên quan BCtrong m-file B.mC.m, tương ứng, mà bạn cũng muốn để có thể gọi D, EF. Dưới đây là một số tùy chọn bạn có:

  • Đặt D, EFmỗi năm riêng riêng m-file của họ, cho phép bất kỳ chức năng khác để gọi cho họ. Nhược điểm là phạm vi của các chức năng này là lớn và không bị giới hạn chỉ A, BC, nhưng xu hướng tăng là điều này khá đơn giản.

  • Tạo một defineMyFunctionsm-file (như trong Jonas' chẳng hạn) với D, EFnhư các chức năng địa phương và một chức năng chính mà chỉ đơn giản là lợi nhuận hoạt động xử lý đối với họ. Điều này cho phép bạn để giữ D, EFtrong cùng một tập tin, nhưng nó không làm bất cứ điều gì liên quan đến phạm vi của các chức năng này từ bất kỳ chức năng mà có thể gọi defineMyFunctionscó thể gọi họ. Sau đó, bạn cũng phải lo lắng về việc chuyển các hàm xử lý xung quanh thành đối số để đảm bảo bạn có chúng ở nơi bạn cần chúng.

  • Sao chép D, EFvào B.mC.mnhư các chức năng địa phương. Điều này giới hạn phạm vi sử dụng của chúng chỉ A, BC, nhưng làm cho việc cập nhật và bảo trì mã của bạn trở thành một cơn ác mộng vì bạn có ba bản sao của cùng một mã ở những nơi khác nhau.

  • Sử dụng các chức năng riêng tư ! Nếu bạn có A, BCtrong cùng thư mục, bạn có thể tạo một thư mục con gọi privatevà địa điểm D, EFtrong đó, mỗi khi một m-file riêng biệt. Điều này giới hạn phạm vi của họ để họ chỉ có thể được gọi bằng chức năng trong thư mục ngay trên (ví dụ A, BC) và giữ chúng lại với nhau trong cùng một vị trí (nhưng vẫn khác nhau m-files):

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

Tất cả điều này nằm ngoài phạm vi câu hỏi của bạn và có thể chi tiết hơn bạn cần, nhưng tôi nghĩ có lẽ sẽ tốt khi chạm vào mối quan tâm chung hơn về việc tổ chức tất cả các tệp m của bạn. ;)


3
Tùy chọn trả lời yêu thích trông như thế này ^, @idigas
embert 4/03/2015

1
@embert Tôi cho rằng anh ta có nghĩa là dọc theo dòng câu hỏi, có thể được bình chọn độc lập với favourating.
OJFord

78

Nói chung, câu trả lời cho câu hỏi của bạn là không, bạn không thể xác định nhiều hơn một chức năng hiển thị bên ngoài cho mỗi tệp. Tuy nhiên, bạn có thể trả về các hàm xử lý cho các hàm cục bộ và một cách thuận tiện để làm như vậy là biến chúng thành các trường của một cấu trúc. Đây là một ví dụ:

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

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

function z=fun2
  z=1;
end

Và đây là cách nó có thể được sử dụng:

>> myfuns = makefuns;
>> myfuns.fun1(5)    
ans =
     5
>> myfuns.fun2()     
ans =
     1

36

Cách duy nhất để có nhiều hàm, có thể truy cập riêng biệt trong một tệp là xác định PHƯƠNG PHÁP TÌNH TRẠNG bằng cách sử dụng lập trình hướng đối tượng . Bạn sẽ truy cập chức năng như myClass.static1(), myClass.static2()v.v.

Chức năng OOP chỉ được hỗ trợ chính thức kể từ R2008a, vì vậy trừ khi bạn muốn sử dụng cú pháp OOP cũ, không có giấy tờ, câu trả lời cho bạn là không, như @gnovice giải thích .

BIÊN TẬP

Một cách nữa để xác định nhiều chức năng bên trong một tệp có thể truy cập từ bên ngoài là tạo một hàm trả về nhiều hàm xử lý . Nói cách khác, bạn sẽ gọi hàm xác định của mình là [fun1,fun2,fun3]=defineMyFunctions, sau đó bạn có thể sử dụng, out1=fun1(inputs)v.v.


Tôi sẽ không sử dụng oop cho mục đích này, nó thêm một chi phí đáng kể đặc biệt là cho các phương thức tĩnh. ( stackoverflow.com/questions/1693429/
Daniel

1
@Daniel: Chi phí trên chỉ đáng chú ý nếu bạn thực hiện một số lượng lớn các lệnh gọi hàm và các phép tính trong phương thức này gần như tức thời. Cả hai điều kiện thường chỉ đến thiết kế xấu - không có vector hóa và các chức năng vô nghĩa. Vì vậy, tôi sẽ không quá lo lắng.
Jonas

23

Tôi thực sự thích câu trả lời của SCFbler - Tôi muốn chỉ ra rằng nó có thể dễ dàng được sửa đổi để nhập các hàm trực tiếp vào không gian làm việc bằng cách sử dụng hàm gán. (Làm như thế này nhắc nhở tôi rất nhiều về cách làm "nhập x từ y" của Python)

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

Và sau đó được sử dụng như vậy:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1

assignin('caller',...)sẽ đúng hơn Bạn có thể muốn sử dụng các chức năng này từ bên trong chức năng khác.
Cris Luengo

10

Cùng dòng với câu trả lời của SCFbler, nhưng với vòng quay kiểu C # nhiều hơn ..

Tôi sẽ (và thường làm) tạo một lớp chứa nhiều phương thức tĩnh. Ví dụ:

classdef Statistics

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

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

end

Vì các phương thức là tĩnh nên bạn không cần phải kích hoạt lớp. Bạn gọi các chức năng như sau:

data = 1:10;

mean = Statistics.MyMean(data);
std = Statistics.MyStd(data);     

4

Tôi xác định nhiều hàm trong một tệp .m bằng Octave và sau đó sử dụng lệnh từ trong tệp .m nơi tôi cần sử dụng các hàm từ tệp đó:

source("mycode.m");

Không chắc chắn nếu điều này có sẵn với 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

Bạn cũng có thể nhóm các chức năng trong một tệp chính cùng với chức năng chính trông như thế này:

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

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

Sau đó, gọi subfun1 sẽ như thế này: str = main ('subfun1')


0

Kể từ R2017b, điều này là không chính thức. Các tài liệu liên quan nêu rằng:

Các tệp chương trình có thể chứa nhiều chức năng. Nếu tệp chỉ chứa định nghĩa hàm, thì hàm đầu tiên là hàm chính và là hàm mà MATLAB liên kết với tên tệp. Các hàm tuân theo chức năng chính hoặc mã script được gọi là các hàm cục bộ. Các chức năng cục bộ chỉ có sẵn trong tập tin.

Tuy nhiên, cách giải quyết được đề xuất trong các câu trả lời khác có thể đạt được điều gì đó tương tự.


Đây không phải là chính xác những gì Gnovice đã nêu ở đầu câu trả lời của mình?
Adiel

@Adiel Có lẽ, nhưng vài năm đã trôi qua kể từ câu trả lời đó, và ai đó có thể tự hỏi liệu có gì thay đổi không.
Dev-iL

Tôi vẫn không nhận được nếu có gì thay đổi ...? :)
Adiel

Không. Khác với có thể một số tài liệu đã được thêm vào để giải quyết chủ đề cụ thể này.
Dev-iL

Lý do tại sao tôi viết câu trả lời này là vì một số bản phát hành trước đây họ đã giới thiệu các chức năng mà bạn có thể thêm vào cuối tập lệnh - vì vậy người ta có thể tự hỏi liệu có gì thay đổi về vấn đề này không (câu trả lời: không).
Dev-iL

-1

Tôi đã thử với SCFRench và với Ru Hasha trên quãng tám.

Và cuối cùng nó hoạt động: nhưng tôi đã thực hiện một số sửa đổi

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

Có thể được gọi trong tệp 'm' khác:

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

cập nhật:

Tôi đã thêm một câu trả lời vì cả +72 và +20 đều không hoạt động trong quãng tám cho tôi. Bài viết mà tôi đã viết hoàn hảo (và tôi đã kiểm tra nó vào thứ Sáu tuần trước khi tôi viết bài sau).


2
Nếu bạn có thể giải thích điều này khác với hai câu trả lời hiện có mà bạn đang sao chép từ đâu, tôi sẽ xóa phần dưới của tôi. Xin lỗi vì đã không bình luận sớm hơn. Tôi chỉ không thấy điều này khác nhau như thế nào, ngoại trừ bạn kết hợp cả hai phương thức thành một hàm và do đó đang làm một cái gì đó dư thừa. Ngoài ra, vui lòng chèn các liên kết thích hợp vào các câu trả lời bạn đang tham khảo, "+72" và "+20" khá khó hiểu, tôi phải mất một thời gian để nhận ra bạn đang tham khảo số phiếu bầu, sẽ thay đổi theo thời gian và đưa ra các tham chiếu của bạn khó hiểu
Cris Luengo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.