Ruby字符串通过引用函数参数传递

时间:2016-10-12 09:16:03

标签: ruby pass-by-reference

Ruby noob here

我理解ruby确实通过函数参数的引用传递

然而,我感觉这与传统的c / c ++风格通过引用

略有不同

示例代码:

def test1(str)
    str += ' World!'
end

def test2(str)
    str << ' World!'
end

str = 'Hello'

test1(str)
p str # Hello

test2(str)
p str # Hello World!

如果我在c / c ++中使用引用,我希望test1也返回Hello World!

这只是出于好奇 - 任何解释都会受到赞赏

5 个答案:

答案 0 :(得分:5)

  

我理解ruby确实通过函数参数的引用传递

Ruby始终是严格按值传递的。 Ruby中没有任何pass-by-reference。

  

这只是出于好奇 - 任何解释都会受到赞赏

为什么你的代码片段没有显示你期望传递引用的结果的简单解释是Ruby不是通过引用传递的。它是按值传递的,您的代码段证明了这一点。

这是一个小片段,它表明Ruby实际上是按值传递而不是通过引用传递:

#!/usr/bin/env ruby

def is_ruby_pass_by_value?(foo)
  foo << <<~HERE
    More precisely, it is call-by-object-sharing!
    Call-by-object-sharing is a special case of pass-by-value, 
    where the value is always an immutable pointer to a (potentially mutable) value.
  HERE
  foo = 'No, Ruby is pass-by-reference.'
  return
end

bar = ['Yes, of course, Ruby *is* pass-by-value!']

is_ruby_pass_by_value?(bar)

puts bar
# Yes, of course, Ruby *is* pass-by-value!,
# More precisely, it is call-by-object-sharing!
# Call-by-object-sharing is a special case of pass-by-value, 
# where the value is always an immutable pointer to a (potentially mutable) value.

Ruby 确实允许对象变异,是纯函数式语言,如Haskell或Clean。

答案 1 :(得分:1)

在第一种情况下,当您执行str += ' World!'

时创建了一个新对象
str = "Hello"
=> "Hello"
str.object_id
=> 69867706917360
str += " World"
=> "Hello World"
str.object_id
=> 69867706885680

str = "Hello"
=> "Hello"
str.object_id
=> 69867706856200
str << " World"
=> "Hello World"
str.object_id
=> 69867706856200

str = "Hello"
=> "Hello"
str.object_id
=> 69867706786780
str.freeze
=> "Hello"
str << " World"
RuntimeError: can't modify frozen String
str += " World"
=> "Hello World"
  

&#34;&LT;&LT;&#34;是二进制左移运算符。左操作数值向左移动右操作数指定的位数。

所以&#34;&lt;&lt;&#34;没有创建新字符串,str.contact("World")也不会创建新字符串。 方法test1不必对返回的结果做任何事情,你可以试试这个方法:

def test1(str)
    str.concat(' World!')
end

答案 2 :(得分:0)

查看以下对测试的调整,通过显示对象的object_id,您可以轻松查看它是否相同。由于+ =连接,Test1返回另一个String对象,但之后不再使用它。 这看起来像是通过引用传递,但实际上它是指向传递的对象的指针的值。我能找到的最好的explenation是here,作者称之为pass-reference-by-value

def test1(str)
    p ["in test1 before", str.object_id]
  str += ' World!'
  p ["in test1 after", str.object_id]
  str
end

def test2(str)
    p ["in test2", str.object_id]
  str << ' World!'
end

str = 'Hello'
p ["in main", str.object_id]

test1(str)
p str # Hello
p ["after test1", str.object_id]

test2(str)
p str 
p ["after test2", str.object_id]

给出

["in main", 12363600]
["in test1 before", 12363600] # the same object, so pointer to object passed by value    
["in test1 after", 12362976] # returns a new object, the old is unchanged
"Hello"
["after test1", 12363600] # idem
["in test2", 12363600]
"Hello World!"
["after test2", 12363600]
# still the same object

答案 3 :(得分:0)

引用了红宝石,除了数字truefalsenil之类的值以外,还引用了其他内容。

a = "hello"
b = a
a.replace("Hola")
p a # Hola
p b # Hola

您想在开头添加魔术注释。

# frozen_string_literal: true
a = "hello"
b = a
a.replace("Hola") #  can't modify frozen String: "hello" (FrozenError)

答案 4 :(得分:-2)

def test1(str)
    str += ' World!'
end

operator +=是ruby中的一个语法糖。表达式a += b转换为a = a + b。应用于+实例的运算符String创建新的String,它是两个参数的串联。这就是为什么在第一种情况下不修改str的原因。

另外,我想纠正你的陈述:

据我所知,ruby通过函数参数的引用传递

实际上,ruby通过引用传递除“值类型”之外的每个参数 - 即。值niltruefalse和类Fixnum的实例