Ruby - 按引用传递参数还是按值传递参数?

18

我不明白为什么他们Ruby通过值传递所有参数,而同时以下代码证明了相反的情况:

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

如果按值传递,它将打印出444,而不是999

除了那个"@var1"在实例外访问时是一个类变量的事情(你认为123与任何事情有关系吗),以及“wat”,因为你说的话没有任何意义。 - Dave Newton
@DaveNewton,我没懂。 - Incerteza
2
Ruby通过引用传递所有内容,它没有按值传递的概念。你从哪里听说它按值传递参数了? - Terrance Kennedy
2
@TerranceKennedy:那是错误的。Ruby 是纯粹按值传递的,没有传引用的概念。在回答中会有较长的解释。 - Chuck
@TerranceKennedy,我从我的例子中得出了这样的结论。 - Incerteza
显示剩余6条评论
1个回答

74
这个问题让人们感到困惑,因为有一种叫做引用类型的东西,还有一种叫做按引用传递的东西,但它们实际上并没有太多关系。
引用和值以及值是引用的概述:
在按引用传递的情况下,函数的参数是传递到函数中的变量的引用,并且修改参数会修改原始变量。Ruby不是这样的。例如,让我们看看以下代码:
def inc(val)
  val += 1
end

a = 1
inc a
puts a

如果Ruby是一种传递引用的语言,那么这个程序将打印2,因为inc中的val += 1将增加a的值。但事实并非如此。变量val不是变量a的引用 - 它是一个独立的变量,被赋予相同的值。
“等等!”你说。“如果我们处理对象呢?对象变量肯定是通过引用传递的,对吧?”
不是的。
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

如果 Ruby 是按引用传递的话,你永远不会看到 change_string 方法有多恶劣,因为 str = "What, I didn't say anything." 会完全替换 be_nice_to_me 的值为字符串 "What? I didn't say anything."。但实际上,change_string 的罪行被暴露在众人面前。那么,如果 Ruby 不是按引用传递的,这是如何可能的呢?
好吧,还记得我之前谈到的引用类型吗?这就是 Ruby 中的对象。引用类型是一种其值为对其他内容的引用的类型。在这种情况下,变量的值是对字符串 "hello" 的引用。当您传递字符串时,变量的值(即引用)被复制到变量 str 中。现在它们都持有对同一个对象的引用,但 str 不是对 be_nice_to_me 的引用。因此,当您修改对象时,这些更改会显示出来,因为它们都引用同一个对象。但是当您修改一个变量时,另一个变量不会看到它,因为两个变量都不是对另一个变量的引用
所以 Ruby 是按值传递还是按引用传递?它是按值传递的,但所有的值都是引用。

5
有人必须说出来,那我就说吧:1 是一个对象(但是不可变的)。但是,确实术语非常混乱,令人困惑。 - mu is too short
1
@muistooshort 百分之百同意。有趣的是,Chuck在这里用来展示Ruby是(他定义的)按值传递的相同例子,我会用来展示Ruby是(我定义的)按引用传递的。将来我会避免对Ruby中按值/引用传递做出笼统的陈述,因为这似乎更加令人困惑。 - Terrance Kennedy
2
@TerranceKennedy:是的,我完全理解你为什么这样称呼它。你对“按引用传递”的定义更符合人们在现实世界中编程的方式。但不幸的是,我们被半个世纪的计算机科学文献和整个教育系统所束缚,它们仍然使用旧的定义,因此我认为让人们知道“如果你读到‘按引用传递’这个术语,它可能并不是在谈论Ruby”是很重要的。 - Chuck
1
C#有引用类型和值类型,以及按值传递和按引用传递的语义。如果你尝试这四种组合,你会很容易地发现这些概念是完全正交的:https://dev59.com/QmjWa4cB1Zd3GeqPq3zm#12438174 - Jörg W Mittag
1
所以基本上,引用类型就是指针,对吧? - asymmetric
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接