2013-10-16 16 views
7

Tôi có chức năng đánh giá được lưu trong bộ nhớ cache. Là một trong các đối số, nó cần một hàm xử lý. Trong một số trường hợp, chức năng xử lý là không thể tiếp cận, và tôi không hoàn toàn hiểu tại sao. Ví dụ dưới đây cho thấy những gì đã cho tôi bối rối:Khi nào tôi có thể vượt qua một tay cầm chức năng?

>> A.a = @plus; feval(@A.a, 1, 1) 

ans = 

    2 

>> clear A 
>> A.a.a = @plus; feval(@A.a.a, 1, 1) 
Error using feval 
Undefined function 'A.a.a' for input arguments of type 'double'. 

Vì vậy, nếu tôi có một chức năng xử lý được lưu trữ như một thành viên cơ cấu, tôi có thể vượt qua nó cùng tốt nếu nó là một mức độ sâu sắc, nhưng không nếu đó là hai cấp độ sâu. Trong trường hợp sử dụng thực sự của tôi, tôi có cấu trúc D chứa nhiều (117) phiên bản của các lớp khác nhau, vì vậy tôi thực sự có stct.obj.meth, trong đó stct là cấu trúc, obj là một cá thể/đối tượng lớp và meth là một phương thức. Việc vượt qua @stct.obj.meth không thành công, nhưng nếu tôi chỉ định A = stct.obj, thì hãy chuyển @A.meth thành công.

Trong điều kiện nào tôi có thể chuyển một hàm xử lý làm đối số, để nó vẫn có thể truy cập xuống ngăn xếp?


Sửa: Mặc dù trong trường hợp sử dụng ở trên, tôi chỉ đơn giản là có thể loại bỏ các @@plus đã là một chức năng xử lý. Tuy nhiên, xem xét tình hình ở đây:

>> type cltest.m 

classdef cltest < handle 
    methods 
     function C = mymeth(self, a, b) 
      C = a + b; 
     end 
    end 
end 

>> A.a = cltest(); 
>> feval(@A.a.mymeth, 1, 1) 
Error using feval 
Undefined function 'A.a.mymeth' for input arguments of type 'double'. 
>> b = A.a; 
>> feval(@b.mymeth, 1, 1) 

ans = 

    2 

Trong trường hợp này, tôi cần các @ trước A.a.mymeth ...

+0

Tôi không giải thích rõ lý do tại sao '@ Aamymeth' không tạo ra hàm xử lý hợp lệ, nhưng đáng lưu ý rằng trong ví dụ đầu tiên,' @ 'không phải là cần thiết. Bạn có thể sử dụng 'A.a = @plus; feval (A.a, 1,1), 'bởi vì' A.a' đã là một con trỏ hàm. – nispio

+0

@nispio Có. Đó là ý chính của câu trả lời trước đó, giờ đã bị xóa. – gerrit

Trả lời

5

lớp Giới thiệu là một vấn đề lớn đối với MATLAB. Vì vậy, lớn, trên thực tế, rằng họ vẫn không hoạt động đúng ngày hôm nay. Ví dụ của bạn cho thấy rằng truy cập cấu trúc và xung đột truy cập phương thức lớp, bởi vì chúng phải làm quá tải ý nghĩa của dấu chấm '.' và không làm cho nó hoạt động liên tục. Tất cả đều hoạt động tốt hơn hoặc ít hơn khi bạn gọi các phương thức lớp một cách rõ ràng bằng tên của chúng trên bảng điều khiển MATLAB, ví dụ: trong ví dụ của bạn >> A.a.mymeth (1,1). Nhưng khi bạn có bất kỳ loại gián đoạn nào, nó sẽ sớm bị phá vỡ.

Bạn đã cố gắng xử lý hàm bằng >> @A.a.mymeth, mà MATLAB không thể hiểu được, có lẽ vì nó bị nhầm lẫn bởi cấu trúc hỗn hợp/lớp điều. Cố gắng làm việc xung quanh bằng cách sử dụng str2func cũng không hoạt động. Nó hoạt động, một lần nữa, chỉ để truy cập tên rõ ràng, như được hiển thị here. Nó phá vỡ cho ví dụ của bạn, ví dụ: >> str2func('b.mymeth'). Nó thậm chí không hoạt động bên trong lớp. Hãy thử những người khác và xem chúng không thành công.

Ngoài ra, MATLAB không thích cấp cho bạn quyền xử lý của phương thức lớp. Không có chức năng cho nó. Không có cách nào để có được tất cả các chức năng xử lý trong một đi, hoặc thậm chí động bằng một chuỗi tên.

Tôi thấy ba tùy chọn ở đây. Trước tiên, hãy thử thay đổi chương trình của bạn, nếu có thể. Những chức năng này có cần phải ngồi trong một classdef không?

Thứ hai, theo dõi cách giải quyết của bạn hoặc của nispio. Cả hai đều tạo ra một biến tạm thời để giữ một tham chiếu đến cá thể lớp để tạo một truy cập không lẫn lộn với các phương thức thành viên của nó. Vấn đề là, cả hai đều yêu cầu đặt tên rõ ràng chức năng. Bạn phải đặt mã này một cách rõ ràng cho mọi chức năng liên quan. Không có cách nào để trừu tượng hóa điều đó.

Thứ ba, lừa gạt bằng cách đưa ra các biện pháp xử lý lớp học của bạn từ bên trong. Bạn có thể cho chúng ra trong một cấu trúc.

classdef cltest < handle 
    methods 
     function C = mymeth(self, a, b) 
      C = a + b; 
     end 
     function hs = funhandles(self) 
      hs = struct('mymeth', @self.mymeth, ... 
         'mymeth2', @self.mymeth2); 
     end 
    end 
end 

Sau đó, bạn có thể truy cập các tay cầm theo tên, thậm chí động.

>> A.a = cltest; 
>> feval(A.a.funhandles.mymeth, 1, 1); 
>> feval(A.a.funhandles.('mymeth'), 1, 1) 

ans = 

    2 

Nhưng hãy cẩn thận, bằng cách sử dụng, bạn có thể truy cập phương thức Access = private từ bên ngoài.

1

Hãy thử điều này:

feval(@(varargin)A.a.mymeth(varargin{:}),1,1); 

Nó là một chút kludgy, nhưng nó sẽ hoạt động.

EDIT:

Cách nó hoạt động là bằng cách tạo ra một Anonymous Function mà phải mất một số biến của các đối số, và bãi những luận cứ vào phương pháp A.a.mymeth(). Vì vậy, bạn không thực sự chuyển một con trỏ tới hàm A.a.mymeth, bạn đang chuyển một con trỏ tới một hàm mà gọiA.a.mymeth.

Một cách khác để đạt được những điều tương tự mà không sử dụng varargin sẽ là:

feval(@(x,y)A.a.mymeth(x,y),1,1); 

Điều này tạo ra một chức năng vô danh mà chấp nhận hai đối số, và chuyển chúng cùng để A.a.mymeth.

<speculation> Tôi nghĩ rằng nó phải cố hữu theo cách mà hàm unary xử lý toán tử @ hoạt động. Trình phân tích cú pháp Matlab có thể xem @token và quyết định xem token có phải là một hàm hợp lệ hay không. Trong trường hợp của a.mymeth nó là đủ thông minh để quyết định rằng mymeth là một thành viên của a, và sau đó trở lại xử lý thích hợp. Tuy nhiên, khi nó nhìn thấy A.a.mymeth nó có thể phát hiện ra rằng A không phải là một lớp, cũng không A có một thành viên có tên a.mymeth và do đó không tìm thấy hàm hợp lệ.Điều này dường như được hỗ trợ bởi một thực tế rằng công trình này:

A.a.a = @plus; feval(A.a.a,1,1) 

và điều này không:

A.a.a = @plus; feval(@A.a.a,1,1) 

</speculation>

+0

Tôi không nghĩ rằng nó ít kludgy hơn của tôi 'B = A.a; feval (@ b.mymeth, 1, 1) '. Câu hỏi đặt ra là: những gì đang xảy ra ở đây? – gerrit

+0

Bạn phải cẩn thận với cách giải quyết mà bạn đã trình bày, bởi vì nếu bạn kết thúc ghi đè b trước khi gọi 'feval', thì bạn sẽ gặp vấn đề. Xem bài chỉnh sửa của tôi cho bài đăng để được giải thích về lý do giải pháp của tôi hoạt động. – nispio

0

Bạn có thể khắc phục nó bằng cách giới thiệu một chức năng riêng biệt mà sửa chữa những gì @ điều hành không được thực hiện:

function h=g(f) 
x = functions(f); 
if ~strcmp(x.type, 'anonymous') 
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']); 
else 
    h = f; 
end 
end 

Bây giờ ví dụ của bạn:

>> feval(g(@A.a.mymeth), 1, 1) 
ans = 
    2 
>> feval(g(@b.mymeth), 1, 1) 
ans = 
    2 

Tôi nghĩ rằng điều này sẽ có tác động nhỏ nhất trên mã của bạn. Bạn có thể làm cho nó một chút thanh lịch hơn nhưng ít mạnh mẽ và/hoặc có thể đọc được. Phương pháp uplus không được định nghĩa cho function_handle lớp, do đó bạn có thể tạo uplus.m trong thư mục @function_handle đâu đó trong đường dẫn của bạn với nội dung này:

function h=uplus(f) 
x = functions(f); 
if ~strcmp(x.type, 'anonymous') 
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']); 
else 
    h = f; 
end 
end 

Bây giờ bạn chỉ cần sử dụng [email protected] thay vì @.Ví dụ:

>> feval([email protected], 1, 1) 
ans = 
    2 
>> feval([email protected], 1, 1) 
ans = 
    2 
Các vấn đề liên quan