क्या रूबी पास संदर्भ या मूल्य से है?


248
@user.update_languages(params[:language][:language1], 
                       params[:language][:language2], 
                       params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------" 
                + lang_errors.full_messages.inspect

if params[:user]
  @user.state = params[:user][:state]
  success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------" 
                + lang_errors.full_messages.inspect

if lang_errors.full_messages.empty?

@userऑब्जेक्ट विधि lang_errorsमें चर में त्रुटियों को जोड़ता है update_lanugages। जब मैं @userऑब्जेक्ट पर एक सेव करता हूं तो मैं उन त्रुटियों को खो देता हूं जो शुरू में lang_errorsचर में संग्रहीत थे ।

हालांकि मैं जो करने का प्रयास कर रहा हूं वह अधिक हैक होगा (जो काम नहीं कर रहा है)। मैं यह समझना चाहूंगा कि परिवर्तनीय मूल्यों को क्यों धोया जाता है। मैं संदर्भ द्वारा पास को समझता हूं इसलिए मैं यह जानना चाहूंगा कि उस चर में मूल्य को बिना धोए कैसे रखा जा सकता है।


मैं यह भी नोटिस करता हूं कि मैं एक क्लोन ऑब्जेक्ट में उस मूल्य को बनाए रखने में सक्षम हूं
सिड

1
आपको अबे वेलेकर के उत्तर को देखना चाहिए। लेकिन इस पर ब्लॉक के चारों ओर चलने के बाद, यहां मैं इसे कैसे कहूंगा। जब आप किसी ऑब्जेक्ट Foo को किसी प्रक्रिया में पास करते हैं, तो ऑब्जेक्ट के संदर्भ की एक कॉपी पास हो जाती है, बार, मान द्वारा पास। आप उस ऑब्जेक्ट को नहीं बदल सकते हैं जो फू इंगित करता है, लेकिन आप उस ऑब्जेक्ट की सामग्री को बदल सकते हैं जिसे वह इंगित करता है। इसलिए यदि आप एक सरणी पास करते हैं, तो सरणी की सामग्री को बदला जा सकता है, लेकिन आप यह नहीं बदल सकते हैं कि किस सरणी को संदर्भित किया जा रहा है। फू पर अन्य निर्भरता को गड़बड़ाने के बारे में चिंता किए बिना फू के तरीकों का उपयोग करने में सक्षम होने के लिए अच्छा है।
bobbdelsol

जवाबों:


244

पारंपरिक शब्दावली में, रूबी सख्ती से पास-वैल्यू है । लेकिन यह वास्तव में नहीं है कि आप यहां क्या पूछ रहे हैं।

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


88
रूबी पास-बाय-वैल्यू है । कोई इफ नहीं। नहीं, मगर नहीं। कोई अपवाद नहीं। आप को पता है कि क्या रूबी (या किसी अन्य भाषा) है चाहते हैं पारित-दर-संदर्भ या पारित-दर-मूल्य , बस इसे आजमा कर देखें: def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
जोर्ग डब्ल्यू मित्तग

95
@ JörgWMittag: हाँ, लेकिन ओपी का भ्रम वास्तव में शब्दों के सख्त सीएस अर्थ में पास-बाय-वैल्यू या पास-बाय-रेफरेंस नहीं है। वह जो याद कर रहा था वह यह है कि आपके द्वारा पास किए जा रहे "मान" संदर्भ हैं। मैंने महसूस किया कि सिर्फ यह कहना कि "यह पास-बाय-वैल्यू है" पांडित्यपूर्ण होगा और ओपी को एक असंतुष्ट कर देगा, जैसा कि वास्तव में उसका मतलब नहीं है। लेकिन स्पष्टीकरण के लिए धन्यवाद, क्योंकि यह भविष्य के पाठकों के लिए महत्वपूर्ण है और मुझे इसे शामिल करना चाहिए था। (मैं हमेशा अधिक जानकारी सहित और लोगों को भ्रमित नहीं करने के बीच फटा हुआ हूं।)
चक

16
@ जॉर्ग से असहमत। रूबी संदर्भ से गुजरती है, वह सिर्फ संदर्भ बदल देती है। इसके बजाय यह कोशिश करें: फू फू (बार) बार.रेप्लेस का 'संदर्भ' अंत; बाज = 'मूल्य'; foo (baz); "रूबी पास-बाय - # {baz}" है
pguardiario

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

7
रूबी में सब कुछ एक वस्तु है, इसलिए रूबी को न तो मान से पारित किया जाता है और न ही संदर्भ से पारित किया जाता है, कम से कम इस अर्थ में कि वे शब्द C ++ में उपयोग किए जाते हैं। रूबी जो करती है उसका वर्णन करने के लिए "ऑब्जेक्ट संदर्भ द्वारा पास" एक बेहतर तरीका हो सकता है। अंत में, हालांकि, सबसे अच्छा शर्त यह हो सकता है कि इनमें से किसी भी शब्द पर बहुत अधिक अर्थ न लगाया जाए, और बस उस व्यवहार की अच्छी समझ प्राप्त करें जो वास्तव में होता है।
डेविड विनीकी

424

अन्य उत्तर देने वाले सभी सही हैं, लेकिन एक मित्र ने मुझे यह समझाने के लिए कहा और यह वास्तव में क्या है कि रूबी चर कैसे संभालती है, इसलिए मैंने सोचा कि मैं उसके लिए लिखी गई कुछ सरल तस्वीरें / स्पष्टीकरण साझा करूंगा (लंबाई के लिए माफी) और शायद कुछ ओवरसाइम्प्लिफिकेशन):


Q1: क्या होता है जब आप एक नए चर strको एक मान पर असाइन करते हैं 'foo'?

str = 'foo'
str.object_id # => 2000

यहां छवि विवरण दर्ज करें

ए: नामक एक लेबल strबनाया जाता है 'foo'जो ऑब्जेक्ट पर इंगित करता है , जो इस रूबी दुभाषिया की स्थिति के लिए स्मृति स्थान पर होता है 2000


Q2: क्या होता है जब आप मौजूदा चर strका उपयोग करके किसी नई वस्तु को सौंपते हैं =?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

यहां छवि विवरण दर्ज करें

ए: लेबल strअब एक अलग वस्तु की ओर इशारा करता है।


Q3: जब आप एक नया चर निर्दिष्ट क्या होता है =करने के लिए str?

str2 = str
str2.object_id # => 2002

यहां छवि विवरण दर्ज करें

A: नामक एक नया लेबल str2बनाया जाता है जो उसी वस्तु पर इंगित करता है str


Q4: यदि ऑब्जेक्ट द्वारा संदर्भित strऔर str2बदल जाता है तो क्या होता है ?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

यहां छवि विवरण दर्ज करें

ए: दोनों लेबल अभी भी एक ही ऑब्जेक्ट पर इंगित करते हैं, लेकिन वह ऑब्जेक्ट खुद ही म्यूट हो गया है (इसकी सामग्री कुछ और हो गई है)।


यह मूल प्रश्न से कैसे संबंधित है?

यह मूल रूप से वही है जो Q3 / Q4 में होता है; विधि को वैरिएबल / लेबल ( str2) की अपनी निजी प्रति मिलती है जो उसमें पास हो जाती है ( str)। यह परिवर्तन नहीं कर सकता है कि लेबल किस ऑब्जेक्ट को str इंगित करता है , लेकिन यह उस ऑब्जेक्ट की सामग्री को बदल सकता है जो वे दोनों को संदर्भित करते हैं:

str = 'foo'

def mutate(str2)
  puts "str2: #{str2.object_id}"
  str2.replace 'bar'
  str2 = 'baz'
  puts "str2: #{str2.object_id}"
end

str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004

1
रॉबर्ट हेटन ने हाल ही में इस बारे में भी ब्लॉग किया: robertheaton.com/2014/07/22/…
माइकल रेनर

48

रूबी "ऑब्जेक्ट संदर्भ द्वारा पास" का उपयोग करती है

(अजगर की शब्दावली का उपयोग करना।)

कहने के लिए रूबी "पास बाय वैल्यू" या "पास बाय रेफरेंस" वास्तव में सहायक होने के लिए वर्णनात्मक नहीं है। मुझे लगता है कि ज्यादातर लोग इन दिनों इसे जानते हैं, यह शब्दावली ("मूल्य" बनाम "संदर्भ") सी ++ से आता है।

C ++ में, "पास बाय वैल्यू" का अर्थ है कि फंक्शन को वेरिएबल की कॉपी मिलती है और कॉपी में कोई भी बदलाव मूल को नहीं बदलता है। यह वस्तुओं के लिए भी सच है। यदि आप किसी ऑब्जेक्ट चर को मान से पास करते हैं तो संपूर्ण ऑब्जेक्ट (उसके सभी सदस्यों सहित) की प्रतिलिपि हो जाती है और सदस्यों में कोई भी परिवर्तन उन सदस्यों को मूल ऑब्जेक्ट पर नहीं बदलता है। (यह अलग है अगर आप एक पॉइंटर को वैल्यू से पास करते हैं लेकिन रूबी के पास वैसे भी एएफएआईके नहीं है।)

class A {
  public:
    int x;
};

void inc(A arg) {
  arg.x++;
  printf("in inc: %d\n", arg.x); // => 6
}

void inc(A* arg) {
  arg->x++;
  printf("in inc: %d\n", arg->x); // => 1
}

int main() {
  A a;
  a.x = 5;
  inc(a);
  printf("in main: %d\n", a.x); // => 5

  A* b = new A;
  b->x = 0;
  inc(b);
  printf("in main: %d\n", b->x); // => 1

  return 0;
}

आउटपुट:

in inc: 6
in main: 5
in inc: 1
in main: 1

C ++ में, "पास से संदर्भ" का अर्थ है कि फ़ंक्शन को मूल चर तक पहुंच मिलती है। यह एक नया शाब्दिक पूर्णांक निर्दिष्ट कर सकता है और मूल चर का मान तब भी होगा।

void replace(A &arg) {
  A newA;
  newA.x = 10;
  arg = newA;
  printf("in replace: %d\n", arg.x);
}

int main() {
  A a;
  a.x = 5;
  replace(a);
  printf("in main: %d\n", a.x);

  return 0;
}

आउटपुट:

in replace: 10
in main: 10

यदि तर्क कोई वस्तु नहीं है, तो रूबी मान से गुजरता है (C ++ अर्थ में)। लेकिन रूबी में सब कुछ एक वस्तु है, इसलिए रूबी में वास्तव में C ++ अर्थ में कोई पास नहीं है।

रूबी में, "ऑब्जेक्ट संदर्भ द्वारा पास" (पायथन की शब्दावली का उपयोग करने के लिए) का उपयोग किया जाता है:

  • फ़ंक्शन के अंदर, ऑब्जेक्ट के किसी भी सदस्य के पास नए असाइन किए गए मान हो सकते हैं और ये परिवर्तन फ़ंक्शन के वापस आने के बाद बने रहेंगे। *
  • फ़ंक्शन के अंदर, वैरिएबल को एक पूरी नई ऑब्जेक्ट असाइन करने से वैरिएबल पुरानी ऑब्जेक्ट को संदर्भित करना बंद कर देता है। लेकिन फ़ंक्शन के लौटने के बाद, मूल चर अभी भी पुरानी वस्तु का संदर्भ देगा।

इसलिए रूबी C ++ अर्थ में "पास बाय रेफरेंस" का उपयोग नहीं करता है। यदि ऐसा होता है, तो एक फ़ंक्शन के अंदर एक चर के लिए एक नई वस्तु को असाइन करने से पुराने ऑब्जेक्ट को फ़ंक्शन वापस आने के बाद भूल जाने का कारण होगा।

class A
  attr_accessor :x
end

def inc(arg)
  arg.x += 1
  puts arg.x
end

def replace(arg)
  arg = A.new
  arg.x = 3
  puts arg.x
end

a = A.new
a.x = 1
puts a.x  # 1

inc a     # 2
puts a.x  # 2

replace a # 3
puts a.x  # 2

puts ''

def inc_var(arg)
  arg += 1
  puts arg
end

b = 1     # Even integers are objects in Ruby
puts b    # 1
inc_var b # 2
puts b    # 1

आउटपुट:

1
2
2
3
2

1
2
1

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


आपका जवाब सबसे अच्छा है। मैं एक साधारण उदाहरण पोस्ट करना चाहता हूं def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"
जुंग

यह सही जवाब है! यह भी यहाँ बहुत अच्छी तरह से समझाया गया है: robertheaton.com/2014/07/22/… । लेकिन जो मुझे अभी भी समझ नहीं आ रहा है वह यह है def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}":। यह प्रिंट "रूबी पास-बाय-वैल्यू" है। लेकिन अंदर fooका चर पुन: सौंपा गया है। यदि barएक सरणी होगा रीअसाइनमेंट प्रभाव नहीं होगा baz। क्यों?
हैफला

मैं आपके सवाल को नहीं समझता। मुझे लगता है कि आपको यहां टिप्पणियों में पूछने के बजाय एक नया प्रश्न पूछना चाहिए।
डेविड विनीकी

42

क्या रूबी पास संदर्भ या मूल्य से है?

रूबी पास-बाय-वैल्यू है। हमेशा। कोई अपवाद नहीं। कोई इफ नहीं। नहीं, मगर नहीं।

यहाँ एक सरल कार्यक्रम है जो उस तथ्य को प्रदर्शित करता है:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value

15
@ दाविद: "यहां गलती यह है कि स्थानीय पैरामीटर को फिर से असाइन किया गया है (स्मृति में एक नए स्थान पर इंगित किया गया है)" - यह एक गलती नहीं है, जो पास-दर-मूल्य की परिभाषा है । यदि रूबी पास-बाय-रेफरेंस थी, तो कैली में बाध्यकारी स्थानीय विधि तर्क को पुन: असाइनमेंट भी कॉलर में स्थानीय चर बंधन को पुन: सौंप दिया होगा। यह नहीं किया। एर्गो, रूबी पास-बाय-वैल्यू है। यह तथ्य कि यदि आप एक परिवर्तनशील मूल्य को बदलते हैं, तो मूल्य परिवर्तन पूरी तरह से अप्रासंगिक है, बस यही है कि कैसे परिवर्तनशील राज्य काम करता है। रूबी एक शुद्ध कार्यात्मक भाषा नहीं है।
जोर्ग डब्ल्यू मित्तग

5
"पास-बाय-वैल्यू" की सही परिभाषा का बचाव करने के लिए जॉर्ग का धन्यवाद। यह स्पष्ट रूप से हमारे मस्तिष्क को पिघला रहा है जब मूल्य वास्तव में एक संदर्भ है, हालांकि माणिक हमेशा मूल्य से गुजरता है।
डगलस

9
यह परिष्कार है। "पास बाय वैल्यू" और "रेफ़र बाई पास" के बीच का व्यावहारिक अंतर एक शब्दार्थ है, वाक्य-विन्यास नहीं। क्या आप कहेंगे कि C सरणियाँ पास-बाय-वैल्यू हैं? बेशक, भले ही जब आप किसी फ़ंक्शन के लिए किसी सरणी का नाम पास करते हैं, तो आप एक अपरिवर्तनीय पॉइंटर पास कर रहे हैं, और केवल वह डेटा जिसके लिए पॉइंटर संदर्भित होता है, उत्परिवर्तित किया जा सकता है। रूबी में स्पष्ट रूप से मूल्य प्रकार मान द्वारा पारित किए जाते हैं, और संदर्भ प्रकार संदर्भ द्वारा पारित किए जाते हैं।
dodgethesteamroller

3
@dodgethesteamroller: रूबी और सी दोनों पास-पास मूल्य हैं। हमेशा। कोई अपवाद नहीं, अगर नहीं, लेकिन नहीं। पास-दर-मूल्य और पास-दर-संदर्भ के बीच का अंतर यह है कि क्या आप संदर्भ बिंदुओं को मान पास करते हैं या संदर्भ पास करते हैं। C हमेशा मान पास करता है, संदर्भ कभी नहीं । मान एक सूचक हो सकता है या नहीं भी हो सकता है, लेकिन क्या मूल्य अप्रासंगिक है कि क्या यह पहली जगह में पारित किया जा रहा है। रूबी भी हमेशा मान से गुजरती है, संदर्भ कभी नहीं । वह मूल्य हमेशा एक सूचक है, लेकिन फिर से, यह अप्रासंगिक है।
जोर्ग डब्ल्यू मित्तग

44
यह जवाब, जबकि कड़ाई से सच बोल रहा है , बहुत उपयोगी नहीं है । तथ्य यह है कि पारित किया जा रहा मूल्य हमेशा एक सूचक है अप्रासंगिक नहीं है । यह उन लोगों के लिए भ्रम का स्रोत है जो सीखने की कोशिश कर रहे हैं, और आपका जवाब उस भ्रम की मदद करने के लिए बिल्कुल कुछ नहीं करता है।

20

रूबी एक सख्त अर्थ में पास-बाय-वैल्यू है, लेकिन मान संदर्भ हैं।

इसे " पास-संदर्भ-दर-मूल्य " कहा जा सकता है । इस लेख में मेरे द्वारा पढ़ी गई सर्वश्रेष्ठ व्याख्या है: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/

पास-संदर्भ-मूल्य को संक्षेप में इस प्रकार समझाया जा सकता है:

एक फ़ंक्शन कॉल करने वाले द्वारा उपयोग की जाने वाली मेमोरी में एक ही ऑब्जेक्ट (और एक्सेस करेगा) के लिए एक संदर्भ प्राप्त करता है। हालाँकि, यह बॉक्स प्राप्त नहीं करता है कि कॉलर इस ऑब्जेक्ट को स्टोर कर रहा है; पास-वैल्यू-बाय-वैल्यू में, फ़ंक्शन अपना स्वयं का बॉक्स प्रदान करता है और अपने लिए एक नया चर बनाता है।

परिणामी व्यवहार वास्तव में पास-बाय-रेफरेंस और पास-बाय-वैल्यू की शास्त्रीय परिभाषाओं का एक संयोजन है।


रूबी के तर्क पास करने का वर्णन करने के लिए मैं उसी वाक्यांश "वैल्यू बाय पास" का उपयोग करता हूं। मुझे लगता है कि यह सबसे सटीक और संक्षिप्त वाक्यांश है।
वेन कॉनराड

16

पहले से ही कुछ शानदार जवाब हैं, लेकिन मैं इस विषय पर अधिकारियों की एक जोड़ी की परिभाषा पोस्ट करना चाहता हूं, लेकिन यह भी उम्मीद कर रहा है कि कोई व्यक्ति यह बता सकता है कि अधिकारियों ने मात्ज़ (रूबी के निर्माता) और डेविड फ्लानगन ने अपनी उत्कृष्ट ओ'रेली पुस्तक में क्या मतलब है, रूबी प्रोग्रामिंग भाषा

[3.8.1 से: ऑब्जेक्ट संदर्भ]

जब आप किसी विधि को रूबी में पास करते हैं, तो यह एक वस्तु संदर्भ होता है जिसे विधि को पास किया जाता है। यह स्वयं वस्तु नहीं है, और यह वस्तु के संदर्भ का संदर्भ नहीं है। यह कहने का एक और तरीका यह है कि विधि तर्कों को संदर्भ के बजाय मूल्य द्वारा पारित किया जाता है , लेकिन यह कि मान दिए गए ऑब्जेक्ट संदर्भ हैं।

क्योंकि ऑब्जेक्ट संदर्भ विधियों के लिए दिए गए हैं, तो अंतर्निहित संदर्भ को संशोधित करने के लिए विधियाँ उन संदर्भों का उपयोग कर सकती हैं। ये संशोधन तब दिखाई देते हैं जब विधि वापस आती है।

यह सब मेरे लिए समझ में आता है जब तक कि अंतिम पैराग्राफ, और विशेष रूप से अंतिम वाक्य। यह सबसे अधिक भ्रामक है, और इससे भी बदतर स्थिति में है। किसी भी तरह से, उस पारित-दर-मूल्य संदर्भ में संशोधन से अंतर्निहित वस्तु कैसे बदल सकती है?


1
क्योंकि संदर्भ संशोधित नहीं हो रहा है; अंतर्निहित वस्तु है
dodgethesteamroller

1
क्योंकि वस्तु परस्पर है। रूबी विशुद्ध रूप से कार्यात्मक भाषा नहीं है। यह पूरी तरह से पास-बाय-रेफरेंस बनाम पास-बाय-वैल्यू के लिए पूरी तरह से ऑर्थोगोनल है (इस तथ्य को छोड़कर कि विशुद्ध रूप से कार्यात्मक भाषा में, पास-बाय-वैल्यू और पास-बाय-संदर्भ हमेशा एक ही परिणाम देते हैं, इसलिए भाषा हो सकती है उपयोग या तो या आप दोनों के बिना कभी जानकर)।
जॉर्ग डब्ल्यू मित्तग

एक अच्छा उदाहरण यह होगा कि यदि किसी फ़ंक्शन में वेरिएबल असाइनमेंट के बजाय, आप किसी फ़ंक्शन को हैश पास करने और मर्ज करने के मामले को देखते हैं! पारित हैश पर। मूल हैश संशोधित समाप्त होता है।
एलसी

16

क्या रूबी पास संदर्भ या मूल्य से है?

रूबी पास-बाय-रेफरेंस है। हमेशा। कोई अपवाद नहीं। कोई इफ नहीं। नहीं, मगर नहीं।

यहाँ एक सरल कार्यक्रम है जो उस तथ्य को प्रदर्शित करता है:

def foo(bar)
  bar.object_id
end

baz = 'value'

puts "#{baz.object_id} Ruby is pass-by-reference #{foo(baz)} because object_id's (memory addresses) are always the same ;)"

=> 2279146940 रूबी पास-बाई-रेफरेंस 2279146940 है क्योंकि ऑब्जेक्ट_ड (मेमोरी एड्रेस) हमेशा एक जैसे होते हैं;)

def bar(babar)
  babar.replace("reference")
end

bar(baz)

puts "some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-#{baz}"

=> कुछ लोगों को इसका संदर्भ नहीं है क्योंकि स्थानीय असाइनमेंट पूर्वता ले सकता है, लेकिन यह स्पष्ट रूप से पास-बाय-संदर्भ है


यह एकमात्र सही उत्तर है और कुछ अच्छे गोचरों को प्रस्तुत करता है: एक = 'फोबार' आज़माएं; बी = ए; b [5] = 'z', a और b दोनों संशोधित हो जाएंगे।
मार्टिज़न

2
@Martijn: आपका तर्क पूरी तरह से मान्य नहीं है। आइए अपने कोड स्टेटमेंट के माध्यम से बयान करें। a = 'foobar' एक नया संदर्भ बनाता है जो 'foobar' की ओर इशारा करता है। b = एक ही डेटा के लिए दूसरा संदर्भ बनाता है a। b [५] = 'z ’b द्वारा संदर्भित मूल्य के छठे वर्ण को एक' z’ में बदलता है (संयोग से जो मूल्य संयोगवश भी परिवर्तित हो जाता है)। इसीलिए आपकी शर्तों में "दोनों संशोधित हो जाते हैं", या अधिक सटीक रूप से, "दोनों चर द्वारा संदर्भित मूल्य क्यों संशोधित हो जाते हैं"।
लुकास_सिक्वलकर

2
आप अपनी barविधि में संदर्भ के साथ कुछ भी नहीं कर रहे हैं । आप केवल उस ऑब्जेक्ट को संशोधित कर रहे हैं जो संदर्भ को इंगित करता है, लेकिन संदर्भ को ही नहीं। वे केवल रूबी में संदर्भ को संशोधित करने का तरीका असाइनमेंट द्वारा है। आप रूबी में विधियों को कॉल करके संदर्भों को संशोधित नहीं कर सकते हैं क्योंकि तरीकों को केवल वस्तुओं पर बुलाया जा सकता है और संदर्भ रूबी में ऑब्जेक्ट नहीं हैं। आपका कोड नमूना दर्शाता है कि रूबी ने परस्पर स्थिति साझा की है (जो यहां चर्चा के अधीन नहीं है), लेकिन यह पास-दर-मूल्य और पास-दर-संदर्भ के बीच अंतर को रोशन करने के लिए कुछ भी नहीं करता है।
जोर्ग डब्ल्यू मित्तग

1
जब कोई पूछता है कि क्या कोई भाषा "पास-बाय-रेफरेंस" है, तो वे आम तौर पर जानना चाहते हैं कि आप किसी फ़ंक्शन के लिए कुछ पास करते हैं और फ़ंक्शन इसे संशोधित करता है, क्या यह फ़ंक्शन के बाहर संशोधित किया जाएगा। रूबी के लिए इसका जवाब 'हां' है। यह उत्तर यह प्रदर्शित करने में मददगार है कि, @ JörgWMittag का उत्तर बेहद ही अनपेक्षित है।
टॉबी 1 केनोबी

@ Toby1Kenobi: आप निश्चित रूप से "पास-बाय-वैल्यू" शब्द की अपनी व्यक्तिगत परिभाषा का उपयोग करने के लिए स्वतंत्र हैं जो आम, व्यापक रूप से उपयोग की जाने वाली परिभाषा से अलग है। हालांकि, यदि आप ऐसा करते हैं, तो आपको लोगों को भ्रमित होने के लिए तैयार रहना चाहिए, खासकर यदि आप इस तथ्य का खुलासा करने की उपेक्षा करते हैं कि आप बहुत अलग बात कर रहे हैं, कुछ पहलुओं में हर किसी की तुलना में धारणा भी विपरीत है। विशेष रूप से, "पारित-दर-संदर्भ" है नहीं के साथ संबंध है या नहीं, "कुछ" है कि पारित हो जाता है संशोधित किया जा सकता है, बल्कि साथ क्या "कुछ" विशेष रूप से है, चाहे वह संदर्भ ... है कि
Jörg डब्ल्यू मितग


2

इसे इस्तेमाल करे:--

1.object_id
#=> 3

2.object_id
#=> 5

a = 1
#=> 1
a.object_id
#=> 3

b = 2
#=> 2
b.object_id
#=> 5

पहचानकर्ता में मान ऑब्जेक्ट 1 के लिए ऑब्जेक्ट_आईडी 3 और पहचानकर्ता बी में ऑब्जेक्ट ऑब्जेक्ट 2 के लिए ऑब्जेक्ट_आईडी 5 होता है।

अब यह करना:--

a.object_id = 5
#=> error

a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2

a.object_id 
#=> 5

अब, a और b दोनों में समान object_id 5 शामिल है जो मान ऑब्जेक्ट 2 को संदर्भित करता है। इसलिए, Ruby वैरिएबल में ऑब्जेक्ट ऑब्जेक्ट्स को संदर्भित करने के लिए object_ids होते हैं।

निम्न करने से भी त्रुटि मिलती है: -

c
#=> error

लेकिन ऐसा करने से त्रुटि नहीं होगी: -

5.object_id
#=> 11

c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11 

a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true

a
#=> Value at a
#=> 11

यहां आइडेंटीफायर एक रिटर्न वैल्यू ऑब्जेक्ट 11 है जिसका ऑब्जेक्ट आईडी 23 है। ऑब्जेक्ट 23 पर आइडेंटिफायर ए है, अब हम विधि का उपयोग करके एक उदाहरण देखते हैं।

def foo(arg)
  p arg
  p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23

foo में arg को x के रिटर्न वैल्यू के साथ असाइन किया गया है। यह स्पष्ट रूप से दर्शाता है कि तर्क को मान 11 से पारित किया जाता है, और मान 11 को एक वस्तु होने के कारण अद्वितीय ऑब्जेक्ट आईडी 23 है।

अब इसे भी देखें: -

def foo(arg)
  p arg
  p arg.object_id
  arg = 12
  p arg
  p arg.object_id
end

#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23

यहाँ, पहचानकर्ता arg में पहले 11 को संदर्भित करने के लिए object_id 23 होता है और मान ऑब्जेक्ट 12 के साथ आंतरिक असाइनमेंट के बाद, इसमें object_id 25 होता है। लेकिन यह कॉलिंग पद्धति में उपयोग किए गए पहचानकर्ता x द्वारा संदर्भित मान को परिवर्तित नहीं करता है।

इसलिए, रूबी मूल्य से गुजरती है और रूबी चर में मान नहीं होते हैं लेकिन मूल्य वस्तु के संदर्भ में होते हैं।


1

रूबी की व्याख्या की जाती है। चर डेटा के संदर्भ हैं, लेकिन डेटा ही नहीं। यह विभिन्न प्रकारों के डेटा के लिए एक ही चर का उपयोग करने की सुविधा देता है।

Lhs = rhs का असाइनमेंट फिर rhs पर संदर्भ की प्रतिलिपि बनाता है, न कि डेटा पर। यह अन्य भाषाओं में भिन्न होता है, जैसे C, जहां असाइनमेंट rhs से lhs के लिए एक डेटा कॉपी करता है।

तो फंक्शन कॉल के लिए, वेरिएबल पास, x, वास्तव में फंक्शन में एक स्थानीय वेरिएबल में कॉपी किया जाता है, लेकिन x एक संदर्भ है। फिर एक ही डेटा को संदर्भित करते हुए, संदर्भ की दो प्रतियां होंगी। एक कॉलर में होगा, एक फंक्शन में।

फ़ंक्शन में असाइनमेंट फिर फ़ंक्शन के संस्करण x के लिए एक नया संदर्भ कॉपी करेगा। इसके बाद x का कॉलर संस्करण अपरिवर्तित रहता है। यह अभी भी मूल डेटा का संदर्भ है।

इसके विपरीत, x पर .replace पद्धति का उपयोग करने से माणिक को डेटा कॉपी करने में मदद मिलेगी। यदि किसी नए असाइनमेंट से पहले रिप्लेसमेंट का उपयोग किया जाता है तो वास्तव में कॉल करने वाले को इसके संस्करण में भी डेटा परिवर्तन दिखाई देगा।

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

'' कॉल बाय वैल्यू '' या 'कॉल बाय रेफरेंस' यहाँ गड़बड़ है क्योंकि '=' संकलित भाषाओं में '=' ​​एक डेटा कॉपी है। यहाँ इस व्याख्या की गई भाषा में '=' ​​एक संदर्भ प्रति है। उदाहरण में आपके पास एक संदर्भ प्रतिलिपि द्वारा पारित संदर्भ है, हालांकि '=' जो मूल संदर्भ में क्लोब करता है, और फिर लोग इसके बारे में बात करते हैं जैसे कि '=' एक डेटा कॉपी थे।

परिभाषाओं के अनुरूप होने के लिए हमें '.replace' को रखना चाहिए क्योंकि यह एक डेटा कॉपी है। '.Replace' के परिप्रेक्ष्य से हम देखते हैं कि यह वास्तव में संदर्भ से गुजरता है। इसके अलावा, अगर हम डीबगर में चलते हैं, तो हम संदर्भों को पास करते हुए देखते हैं, क्योंकि चर संदर्भ हैं।

हालाँकि अगर हमें '=' ​​को संदर्भ के एक फ्रेम के रूप में रखना चाहिए, तो वास्तव में हम एक असाइनमेंट तक डेटा को पारित करने के लिए देखते हैं, और तब हमें असाइनमेंट के बाद इसे देखने के लिए नहीं मिलता है जबकि कॉलर का डेटा अपरिवर्तित रहता है। एक व्यवहारिक स्तर पर यह तब तक मूल्य से गुजरता है जब तक कि हम पारित मूल्य को समग्र नहीं मानते हैं - क्योंकि हम दूसरे भाग को एकल असाइनमेंट में बदलते समय इसका हिस्सा नहीं रख पाएंगे। संदर्भ बदल जाता है और मूल गुंजाइश से बाहर हो जाता है)। एक मस्सा भी होगा, उस उदाहरण में वस्तुओं में चर संदर्भ होंगे, जैसा कि सभी चर हैं। इसलिए हमें 'मूल्य द्वारा संदर्भ' पारित करने के बारे में बात करने के लिए मजबूर किया जाएगा और संबंधित स्थानों का उपयोग करना होगा।


1

यह ध्यान दिया जाना चाहिए कि मूल्य मूल मूल्य को बदलने के लिए आपको "प्रतिस्थापित" पद्धति का उपयोग करने की आवश्यकता नहीं है। यदि आप हैश के लिए किसी एक हैश मान को असाइन करते हैं, तो आप मूल मान बदल रहे हैं।

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"

एक और चीज मुझे मिली। यदि आप एक संख्यात्मक प्रकार पास कर रहे हैं, तो सभी संख्यात्मक प्रकार अपरिवर्तनीय हैं, और इस प्रकार मूल्य से पास होते हैं। ऊपर स्ट्रिंग के साथ काम करने वाले बदले हुए फ़ंक्शन, किसी भी संख्यात्मक प्रकार के लिए काम नहीं करते हैं।
डॉन कार

1
Two references refer to same object as long as there is no reassignment. 

उसी ऑब्जेक्ट में कोई भी अपडेट नई मेमोरी के संदर्भ नहीं बनाएगा क्योंकि यह अभी भी उसी मेमोरी में है। यहाँ कुछ उदाहरण हैं:

    a = "first string"
    b = a



    b.upcase! 
    => FIRST STRING
    a
    => FIRST STRING

    b = "second string"


a
    => FIRST STRING
    hash = {first_sub_hash: {first_key: "first_value"}}
first_sub_hash = hash[:first_sub_hash]
first_sub_hash[:second_key] = "second_value"

    hash
    => {first_sub_hash: {first_key: "first_value", second_key: "second_value"}}

    def change(first_sub_hash)
    first_sub_hash[:third_key] = "third_value"
    end

    change(first_sub_hash)

    hash
    =>  {first_sub_hash: {first_key: "first_value", second_key: "second_value", third_key: "third_value"}}

0

हाँ लेकिन ....

रूबी एक वस्तु के संदर्भ में गुजरती है और चूंकि माणिक में सब कुछ एक वस्तु है, तो आप कह सकते हैं कि यह संदर्भ से गुजरता है।

मैं यहाँ पोस्टिंग से सहमत नहीं हूँ, यह दावा करते हुए कि यह मूल्य से गुज़रा है, यह मुझे पांडित्य, सहानुभूति के खेल जैसा लगता है।

हालांकि, वास्तव में यह व्यवहार को "छुपाता है" क्योंकि ज्यादातर ऑपरेशन रूबी "बॉक्स से बाहर" प्रदान करता है - उदाहरण के लिए स्ट्रिंग ऑपरेशन, ऑब्जेक्ट की एक प्रति उत्पन्न करते हैं:

> astringobject = "lowercase"

> bstringobject = astringobject.upcase
> # bstringobject is a new object created by String.upcase

> puts astringobject
lowercase

> puts bstringobject
LOWERCASE

इसका मतलब यह है कि बहुत समय, मूल वस्तु को अपरिवर्तित छोड़ दिया जाता है, यह देखते हुए कि रूबी "मान से पास" है।

बेशक, अपनी खुद की कक्षाएं डिजाइन करते समय, इस व्यवहार के विवरण की समझ कार्यात्मक व्यवहार, स्मृति दक्षता और प्रदर्शन दोनों के लिए महत्वपूर्ण है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.