2016-02-03 4 views
8

में एक लवल्यू या रावल्यू के रूप में किया जा रहा है, तो मैं कुछ कोड लिख रहा हूं जहां मैं डेटाबेस मूल्यों को पढ़ने और लिखने के लिए एक लवल्यू और रावलू दोनों के रूप में एक सबराउटिन का उपयोग कर रहा हूं। समस्या यह है कि, मैं इसे अलग-अलग प्रतिक्रिया देना चाहता हूं कि इसका उपयोग एक लवल या रावल्यू के रूप में किया जा रहा है या नहीं।जांचें कि क्या एक सबराउटिन का उपयोग लेल

मैं चाहता हूं कि subroutine डेटाबेस में लिखने के लिए जब इसे एक लाइवल्यू के रूप में उपयोग किया जाए, और डेटाबेस से पढ़ें जब इसे एक रावल्यू के रूप में उपयोग किया जाता है।

उदाहरण:

# Write some data 
$database->record_name($subscript) = $value; 

# Read some data 
my $value = $database->record_name($subscript); 

एक ही रास्ता मैं कर इस काम सबरूटीन पहचान क्या यह एक lvalue या एक rvalue के रूप में इस्तेमाल किया जा रहा है और प्रत्येक के लिए अलग प्रतिक्रिया के लिए एक तरीका मिल रहा है के बारे में सोच सकते हैं मामला।

क्या ऐसा करने का कोई तरीका है?

+0

मैं सहमत हूं, लेकिन मैं डेटाबेस एक्सेस के लिए पायथन में उपयोग की जाने वाली एक समान एपीआई की कार्यक्षमता को दर्पण करने की कोशिश कर रहा हूं और ऐसा लगता है कि यह एक एल्यूएलयू सबराउटिन का उपयोग करके यूआई परिप्रेक्ष्य से क्लीनर दिखता है। – tjwrona1992

+0

यदि आप मूस का उपयोग कर रहे हैं तो [MooseX :: LvalueAttribute] (https://metacpan.org/pod/MooseX::LvalueAttribute) है। – ThisSuitIsBlackNot

+2

फैंसी विचार और नीचे दिए गए समाधानों के बावजूद, मुझे यह कहना है कि मैं [ysth] (http://stackoverflow.com/a/35184272/622310) से सहमत हूं जो सुझाव देता है कि आपको केवल '$ डेटाबेस-> record_name ($ subscript, $ value) 'डेटाबेस को लिखने के लिए। फिर आपके सभी सबराउटिन को दूसरे पैरामीटर के अस्तित्व की जांच करना है। इससे कहीं अधिक विस्तृत और आप कोड बनायेंगे कि कोई भी – Borodin

उत्तर

4

यह निर्णय लेना कि को कहा जाता है या नहीं, यह एक बुरा विचार है क्योंकि foo(record_name(...)) इसे एक लवल्यू के रूप में कॉल करेगा।

इसके बजाए, आपको यह तय करना चाहिए कि का उपयोग एक लालसा के रूप में किया गया है या नहीं।

आप magical value लौटकर ऐसा कर सकते हैं।

use Variable::Magic qw(cast wizard); 

my $wiz = wizard(
    data => sub { shift; \@_ }, 
    get => sub { my ($ref, $args) = @_; $$ref = get_record_name(@$args); }, 
    set => sub { my ($ref, $args) = @_; set_record_name(@$args, $$ref); }, 
); 

sub record_name :lvalue { 
    cast(my $rv, $wiz, @_); 
    return $rv; 
} 

एक छोटी सी परीक्षा:

use Data::Dumper; 

sub get_record_name { print("get: @_\n"); return "val"; } 
sub set_record_name { print("set: @_\n"); } 

my $x = record_name("abc", "def");  # Called as rvalue 

record_name("abc", "def") = "xyz";  # Called as lvalue. Used as lvalue. 

my $y_ref = \record_name("abc", "def"); # Called as lvalue. 
my $y = $$y_ref;       # Used as rvalue. 
$$y_ref = "xyz";       # Used as lvalue. 

आउटपुट:

get: abc def 
set: abc def xyz 
get: abc def 
set: abc def xyz 

इसे देखने के बाद आप निश्चित रूप से सीखा है कि आप एक lvalue उप का उपयोग करने का विचार त्याग देना चाहिए। उस जटिलता को छिपाना संभव है (जैसे sentinel का उपयोग करके), लेकिन जटिलता बनी हुई है। कल्पना सभी जटिलताओं के लायक नहीं है। अलग सेटर्स और गेटर्स का उपयोग करें या एक एक्सेसर का उपयोग करें जिसका भूमिका इसके पास पारित पैरामीटर की संख्या ($s=acc(); बनाम acc($s)) पर आधारित है।

+3

द्वारा प्रेरित किया गया था यह उत्तर हास्यास्पद रूप से भ्रमित है। अंत में मैंने पूरी तरह से lvalue subroutines से परहेज करने के लिए जाने का फैसला किया है, लेकिन मैं वास्तव में जादुई मूल्य लौटने के विचार से चिंतित हूँ! – tjwrona1992

+0

@ बोरोडिन: मैंने जो भी करने का फैसला किया है, उसके बावजूद, यह एकमात्र उत्तर है जो वास्तव में प्रश्न का उत्तर देता है और बताता है कि क्या किया गया था। मैं स्वीकार करूंगा कि मैंने इसे स्वयं परीक्षण नहीं किया है, न ही मैं समाधान को पूरी तरह से समझता हूं, लेकिन मुझे कभी भी बुरा जवाब देने के लिए ikegami नहीं पता है, इसलिए मुझे विश्वास है कि यह समाधान काम करेगा। – tjwrona1992

+0

@ tjwrona1992: एक और मुद्दा यह है कि एक सेटर के रूप में 'lvalue' subroutine का उपयोग करना बहुत अजीब होगा, क्योंकि सबराउटिन को रावलू बिल्कुल नहीं दिखता है - यह केवल एक वैरिएबल देता है जिस पर रावल्यू असाइन किया जाएगा, और जब तक कि आप उस ऑब्जेक्ट को वापस न करें जिसमें असाइनमेंट असाइन किया गया हो जो काम नहीं करेगा – Borodin

0

मेरी राय में, पर्ल में लवल्यू सबराउटिन एक बेवकूफ विचार थे। एक गेटर के रूप में बस ->record_name($subscript, $value) को एक सेटटर और ->record_name($subscript) के रूप में समर्थन दें।

कहा कि आप इस

use Want; 

sub record_name:lvalue { 
    if (want('LVALUE')) { 
     ... 
    } 
    else { 
     ... 
    } 
} 

की तरह, Want मॉड्यूल का उपयोग कर सकते हैं कि हालांकि यह भी एक lvalue के रूप में इस का इलाज होगा:

foo($database->record_name($subscript)); 

आप केवल काम के बयानों विशेष रूप से इलाज किया जा करना चाहते हैं , इसके बजाय want('ASSIGN') का उपयोग करें।

+1

समझता है यदि आप 'चाहते हैं (' LVALUE ')' का उपयोग करते हैं, तो 'f (record_name) 'विफल रहता है (माना जाता है कि आप रिकॉर्ड नाम को' f' 'पास करना चाहते हैं)। लेकिन यदि आप 'चाहते हैं (' असाइन करें ') का उपयोग करते हैं, तो रिकॉर्डनाम के लिए '$ _ = 1;' ब्रेक। यह दृष्टिकोण स्वाभाविक रूप से त्रुटिपूर्ण है। – ikegami

+1

@ikegami: yup, यह है। मैंने कुछ ऐसा कोड किया है जो आपके उत्तर की तरह काम करता था, लेकिन यह नहीं पता था कि इसके लिए एक मॉड्यूल था। किसी भी मामले में, पूरी चीज एक चूसने वाला इंटरफ़ेस बनाती है। – ysth

+0

@ysth: 'नहीं चाहते (' RVALUE ')' ठीक काम करना चाहिए – Borodin

4

इस स्थिति के लिए आप मेरे Sentinel मॉड्यूल को आजमा सकते हैं।

यह एक ऐसा फ़ंक्शन प्रदान करता है जिसे आप एक्सेसर में उपयोग कर सकते हैं, इसे अधिक प्राप्त/सेट शैली दृष्टिकोण में बदल सकते हैं। जैसे आप सकता है

use Sentinel qw(sentinel); 

sub get_record_name { ... } 
sub set_record_name { ... } 

sub record_name 
{ 
    sentinel get => \&get_record_name, 
      set => \&set_record_name, 
      obj => shift; 
} 

इस बिंदु पर, कोड की लाइनों के निम्नलिखित जोड़े बराबर

$name = $record->record_name; 
$name = $record->get_record_name; 

$record->record_name = $new_name; 
$record->set_record_name($new_name); 
बेशक

, कर रहे हैं यदि आप तरीकों की विशिष्ट get_ और set_ उपसर्ग के संस्करण प्रदान करने की आवश्यकता होगी, नहीं कर रहे हैं साथ ही, आप उन्हें बंद करने के रूप में इनलाइन कर सकते हैं।

मॉड्यूल दस्तावेज़ों को और विचारों के लिए भी देखें।

संबंधित मुद्दे