2013-10-16 8 views
7

मेरे पास कैश मूल्यांकन के लिए एक फ़ंक्शन है। तर्कों में से एक के रूप में, यह एक फ़ंक्शन हैंडल लेता है। कुछ परिस्थितियों में, फ़ंक्शन हैंडल अप्राप्य है, और मुझे समझ में नहीं आता कि क्यों। उदाहरण के नीचे से पता चलता क्या हो गया मुझे स्टम्प्ड:मैं फ़ंक्शन हैंडल कब पास कर सकता हूं?

>> 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'. 

तो, अगर मैं एक समारोह के लिए एक संरचना सदस्य के रूप में जमा संभाल है, मैं अगर यह एक स्तर गहरी है ठीक साथ इसे पारित कर सकते हैं, लेकिन नहीं करता है, तो यह दो स्तर नीचे है। मेरे असली उपयोग मामले में, मेरे पास एक संरचना D है जिसमें विभिन्न वर्गों के कई (117) उदाहरण हैं, इसलिए मेरे पास वास्तव में stct.obj.meth है, जहां stct एक संरचना है, obj एक क्लास इंस्टेंस/ऑब्जेक्ट है, और meth एक विधि है। @stct.obj.meth पास करने में विफल रहता है, लेकिन अगर मैं A = stct.obj असाइन करता हूं, तो @A.meth उत्तीर्ण हो जाता है।

मैं किस स्थिति के तहत एक फ़ंक्शन हैंडल को तर्क के रूप में पास कर सकता हूं, ताकि यह अभी भी ढेर के नीचे पहुंच योग्य हो?


संपादित: उपरोक्त उपयोग के मामले में हालांकि, मैं उसे आसानी से हटा सकता है @ क्योंकि @plus पहले से ही एक समारोह संभाल है। हालांकि, स्थिति यहां पर विचार करें:

>> 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 

इस मामले में, मैं जरूरत @A.a.mymeth से पहले ...

+0

मैं क्यों '@ Aamymeth' एक वैध समारोह संभाल उत्पादन नहीं करता है के लिए एक अच्छा स्पष्टीकरण की जरूरत नहीं है, लेकिन यह ध्यान देने योग्य बात है कि अपने पहले उदाहरण में अतिरिक्त' @ 'नहीं है लायक है जरूरत है। आप 'एए = @ प्लस का उपयोग कर सकते हैं; feval (एए, 1,1); 'क्योंकि' ए 'पहले से ही एक समारोह सूचक है। – nispio

+0

@ निस्पियो हां। वह पहले की गलती थी, अब हटा दिया गया, जवाब। – gerrit

उत्तर

5

परिचय कक्षाएं MATLAB के लिए एक बड़ी बात थी। वास्तव में, वास्तव में, कि वे अभी भी ठीक से काम नहीं करते हैं। आपका उदाहरण दिखाता है कि संरचना पहुंच और क्लास विधि एक्सेस विवाद, क्योंकि उन्हें डॉट 'अर्थ' के अर्थ को अधिभार करना पड़ा था। और इसे निर्बाध रूप से काम करने के लिए नहीं मिला। जब आप MATLAB कंसोल पर उनके नाम से क्लास विधियों को स्पष्ट रूप से कॉल कर रहे हैं, तो यह सब कुछ कम या कम काम करता है, उदा। आपके उदाहरण में >> ए.ए.मेमेथ (1,1)। लेकिन जब आपके पास किसी प्रकार का संकेत होता है, तो यह जल्द ही टूट जाता है।

आपने >> @A.a.mymeth द्वारा फ़ंक्शन हैंडल प्राप्त करने का प्रयास किया, जो MATLAB को समझ में नहीं आ सकता है, संभवतः क्योंकि यह मिश्रित संरचना/वर्ग की चीज़ से भ्रमित हो जाता है। str2func का उपयोग करके काम करने की कोशिश कर रहा है या तो काम नहीं करता है। यह फिर से स्पष्ट नाम पहुंच के लिए काम करता है, जैसा कि here दिखाया गया है। यह आपके उदाहरण के लिए टूट जाता है, उदा। >> str2func('b.mymeth')। यह कक्षा के अंदर भी काम नहीं करता है। अन्य संकेतों को आजमाएं और उन्हें असफल देखें।

इसके अतिरिक्त, MATLAB आपको क्लास विधि के हैंडल देने को पसंद नहीं करता है। इसके लिए कोई फंक्शन नहीं है। एक नाम स्ट्रिंग द्वारा सभी फ़ंक्शन हैंडल को प्राप्त करने का कोई तरीका नहीं है, या यहां तक ​​कि गतिशील रूप से भी।

मुझे यहां तीन विकल्प दिखाई देते हैं। सबसे पहले, यदि संभव हो, तो अपने प्रोग्राम को बदलने का प्रयास करें। क्या इन कार्यों को कक्षा में बैठने की ज़रूरत है?

दूसरा, अपने या निस्पीओ के कामकाज का पालन करें। वे दोनों अपने सदस्य विधियों में गैर-मिश्रित पहुंच बनाने के लिए कक्षा उदाहरण के संदर्भ में एक अस्थायी चर बनाते हैं। समस्या यह है कि, दोनों को स्पष्ट रूप से फ़ंक्शन नामकरण की आवश्यकता होती है। आपको इस कोड को शामिल प्रत्येक समारोह के लिए स्पष्ट रूप से रखना होगा। उस सार को बाहर करने का कोई तरीका नहीं है।

तीसरा, अपनी कक्षा की विधि को अंदर से हैंडल देकर धोखा देती है। आप उन्हें एक संरचना में दे सकते हैं।

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 

तब आप नाम से भी हैंडल तक पहुंच सकते हैं, यहां तक ​​कि गतिशील रूप से भी।

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

ans = 

    2 

लेकिन सावधानी बरतें, इसका उपयोग करके आप बाहर से एक्सेस = निजी विधियों तक पहुंच सकते हैं।

1

आज़माएं:

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

यह एक छोटे से kludgy है, लेकिन यह काम करना चाहिए।

संपादित करें:

तरह से यह काम करता है एक Anonymous Function कि बहस के परिवर्तनशील लेता है, और विधि A.a.mymeth() में उन तर्कों उदासीनता बनाने के द्वारा है। तो आप वास्तव में फ़ंक्शन एए.मेमेथ के लिए पॉइंटर पास नहीं कर रहे हैं, आप एक फ़ंक्शन को पॉइंटर पास कर रहे हैं जो A.a.mymeth पर कॉल करता है।

varargin का उपयोग कर किया जाएगा बिना एक ही बात को प्राप्त करने का एक वैकल्पिक तरीका:

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

इस को उस अज्ञात फ़ंक्शन दो तर्क स्वीकार करता है बनाता है, और उन्हें A.a.mymeth के साथ गुजरता है।

<speculation> मुझे लगता है कि यह यूनरी फ़ंक्शन हैंडल ऑपरेटर @ काम करता है इस तरह से निहित होना चाहिए। Matlab पार्सर शायद @token पर देखता है और यह तय करता है कि token मान्य कार्य है या नहीं। a.mymeth के मामले में यह तय करने के लिए पर्याप्त स्मार्ट है कि mymetha का सदस्य है, और उसके बाद उपयुक्त हैंडल लौटाएं। हालांकि, जब यह A.a.mymeth देखता है तो यह पता चला है कि A कक्षा नहीं है, न ही A का सदस्य a.mymeth है और इसलिए कोई वैध कार्य नहीं मिला है।यह तथ्य यह है कि यह काम करता है के द्वारा समर्थित किया जा रहा है:

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

और इस कार्य नहीं करता:

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

</speculation>

+0

मुझे नहीं लगता कि यह मेरे 'बी = एए से कम क्लेडी है; feval (@ बी .mymeth, 1, 1) '। सवाल यह है कि यहां क्या हो रहा है? – gerrit

+0

आपको दिखाए गए कामकाज से सावधान रहना होगा, क्योंकि यदि आप 'feval' को कॉल करने से पहले ओवरराइटिंग बी समाप्त करते हैं, तो आपको एक समस्या होगी। मेरा समाधान क्यों काम करता है इस पर एक स्पष्टीकरण के लिए पोस्ट में मेरा संपादन देखें। – nispio

0

आपको इसके चारों ओर एक अलग समारोह है कि सही करता क्या @ ऑपरेटर नहीं कर रहा है शुरू करने से प्राप्त कर सकते हैं:

अपने उदाहरण के लिए
function h=g(f) 
x = functions(f); 
if ~strcmp(x.type, 'anonymous') 
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']); 
else 
    h = f; 
end 
end 

अब:

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

मुझे लगता है कि इस छोटी से छोटी असर पड़ेगा आपके कोड पर आप इसे थोड़ा अधिक सुरुचिपूर्ण लेकिन कम मजबूत और/या पठनीय बना सकते हैं।

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

अब तुम सिर्फ [email protected] बजाय @ उपयोग करने की आवश्यकता: तो तुम uplus.m फ़ोल्डर @function_handle में कहीं अपनी राह में इस सामग्री के साथ बना सकते हैं uplus विधि function_handle वर्ग के लिए निर्धारित नहीं है।आपके उदाहरण के लिए:

>> feval([email protected], 1, 1) 
ans = 
    2 
>> feval([email protected], 1, 1) 
ans = 
    2 
संबंधित मुद्दे