2011-02-04 61 views
30

ví dụ nhỏ:Làm thế nào để bọc một chức năng bằng cách sử dụng varargin và varargout?

function varargout = wrapper(varargin) 
varargout = someFunction(varargin); 

Đó là cách tôi làm điều đó trước tiên. Nhưng ví dụ nếu someFunction = ndgrid điều này mang lại giá trị không được xác định cho lỗi mảng ô, do đó, lần thử tiếp theo sử dụng someFunction(varargin{:}) thay thế. Đó là một cuộc gọi thành công, nhưng gọi số [a,b] = wrapper([1,2], [3,4]) không mang lại kết quả tương tự như cuộc gọi trực tiếp đến ndgrid, vậy tôi đang làm gì sai?

Trả lời

35

Thực ra, câu trả lời của Mikhail là không hoàn toàn đúng. Trong trường hợp hàm someFunction là hàm trả về một giá trị ngay cả khi không có giá trị nào được yêu cầu, đó là cách hàm chỉ ra rằng giá trị sẽ được gán cho ans, trình bao bọc của Mikhail sẽ thất bại. Ví dụ, nếu someFunction được thay thế với tội lỗi và bạn so chạy wrapper so với chạy tội lỗi trực tiếp, bạn sẽ thấy:

>> wrapper(0) 
>> sin(0) 

ans = 

    0 

Cách đúng để làm điều này là

function varargout = wrapper(varargin) 
[varargout{1:nargout}] = someFunction(varargin{:}); 

Lý do làm việc này là do một trường hợp ít được biết đến trong các quy tắc lập chỉ mục MATLAB đã tồn tại chính xác cho trường hợp này vì ít nhất R2006a (có thể lâu hơn). Nó là một cái gì đó của một mụn cóc trong chỉ mục MATLAB nhưng được coi là cần thiết để xử lý loại điều này.

Quy tắc là:

Khi thực hiện nhiệm vụ subscripted, nếu

  • subscripted-gán cho một biến chưa được khởi tạo, VÀ
  • biến chưa được khởi tạo là xoăn-cú đúp lập chỉ mục, VÀ
  • sự chỉ mục trong dấu ngoặc nhọn trống và AND
  • phía bên trái xuất hiện bên trong dấu ngoặc vuông và
  • phía bên phải xử lý thành một giá trị/trả về một đầu ra

Sau đó, biến chưa được khởi tạo được gán một ô vô hướng chứa giá trị được trả về phía bên tay phải.

Ví dụ:

>> clear uninit % just to make sure uninit is uninitialized 
>> [uninit{[]}] = sin(0) 

uninit = 

    [0] 
+1

+1 và cảm ơn thông tin chuyên sâu này! Bạn đã nhận được các quy tắc ở trên ở đâu? – Mikhail

+7

Vâng, thành thật mà nói, nó sẽ giúp nếu bạn có quyền truy cập vào mã nguồn ... Tôi làm việc cho The MathWorks. Tôi không chắc chắn nếu điều này được ghi lại ở bất cứ đâu chính thức. Đó là một trong những điều giúp người dùng nâng cao nhưng có thể dễ dàng gây nhầm lẫn cho người mới bắt đầu. Tuy nhiên, tôi tự tin rằng hành vi này sẽ không thay đổi, bởi vì nó cần thiết để xử lý trường hợp này. – SCFrench

+0

Cảm ơn bạn đã chia sẻ, điều này đã làm tôi thất vọng trong một thời gian dài! – Erik

6
function varargout = wrapper(varargin) 

if ~nargout 
    someFunction(varargin{:}); 
else 
    [varargout{1:nargout}] = someFunction(varargin{:}); 
end 
+0

Oh, bạn đánh tôi để nó bằng 30 giây :) Tôi đã chính xác câu trả lời tương tự. – Edric

1

Nếu số lượng đối số đầu ra là giống như số lượng các đối số đầu vào, bạn có thể sử dụng

function varargout = wrapper(varargin) 
[varargout{1:nargin}] = someFunction(varargin{:}); 

này hoạt động tốt với ndgrid.

+2

Ngoài lỗi đánh máy (bạn chắc chắn có nghĩa là varargout {1: nargout}), lưu ý rằng cách tiếp cận này luôn trả về đầu ra - do đó bảo vệ "~ nargout" bổ sung của Mikhail. – Edric

+0

@Edric: Tôi nghĩ việc sử dụng 'nargin' là vì mục đích giả định' nargout = nargin'. Trong trường hợp đó, bảo vệ '~ nargout' không cần thiết –

+1

@Edric ... cũng thấy [Câu trả lời của SCFrench] (http://stackoverflow.com/questions/4895556/how-to-wrap-a-function-using- varargin-and-varargout/4910926 # 4910926) tại sao bảo vệ thực sự không mang lại hành vi mong muốn –

Các vấn đề liên quan