Ruby - Parameters by reference or by value? [dupli

2019-01-03 02:45发布

问题:

This question already has an answer here:

  • Is Ruby pass by reference or by value? 12 answers

I don't understand why they say Ruby passes all parameters by value and at the same time the following code proves the opposite:

class MyClass1
  @var1 = 123

  def get1
    @var1
  end

  def set1=value
    @var1 = value
  end
end

c1 = MyClass1.new
c1.set1 = 444
p c1.get1 # 444

def test1 mc
  mc.set1 = 999
end

test1 c1
p c1.get1 # 999

If it were by value, it would print out 444, not 999.

回答1:

This question confuses people because there is a thing called a reference type and there is a thing called pass-by-reference, but they don't actually have all that much to do with each other.

References and values and values that are references: A (sorta) brief overview

In a pass-by-reference scenario, the parameters of a function are references to the variables that were passed into the function, and modifying the parameters modifies the original variables. This is not what Ruby is. For example, let's look at the following code:

def inc(val)
  val += 1
end

a = 1
inc a
puts a

If Ruby were a pass-by-reference language, this program would print 2, because the val += 1 in inc would increment the value of a. But that isn't what happens. The variable val is not a reference to the variable a — it's an independent variable that is given the same value.

"But wait!" you say. "What if we were dealing with objects? Surely object variables are passed by reference, right?"

Nope.

def change_string(str)
  str << " I can insult you all you want"
  str << " because you'll never see this"
  str << " because I'm going to replace the whole string!"
  str << " Haha you smell bad!"
  str = "What? I didn't say anything." # I'm so sneaky
end

be_nice_to_me = "hello"
change_string(be_nice_to_me)
puts be_nice_to_me

If Ruby were pass-by-reference, you'd never see how mean the change_string method is, because the str = "What, I didn't say anything." would totally replace the value of be_nice_to_me with the string "What? I didn't say anything." But in fact change_string's sins are laid bare for all to see. How is this possible if Ruby doesn't pass by reference?

Well, remember those reference types I talked about earlier? Well, that's what objects are in Ruby. A reference type is a type whose value is a reference to something else. In this case, the variable's value is a reference to the string "hello". When you pass the string, the variable's value — which is a reference — is copied into the variable str. So now they both hold references to the same object, but str is not a reference to be_nice_to_me. So when you modify the object, those changes show up because they're both referring to the same object. But when you modify one variable, the other doesn't see it because neither variable is a reference to the other.

So is Ruby pass-by-reference or pass-by-value? It's pass-by-value, but all the values are references.



标签: