Ruby 字符串按引用函数参数传递

Ruby string pass by reference function parameter

Ruby 菜鸟在这里

我了解 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 也 return Hello World!

这只是出于好奇 -- 任何解释将不胜感激

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

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

另外我想纠正你的说法:

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

实际上 ruby 通过引用传递每个参数,除了 "value types" - 即。值 niltruefalse 和 class Fixnum

的实例

看看你的测试的以下改编,通过显示你的对象的 object_id 你可以很容易地看出它是否相同。 Test1 returns 另一个 String 对象,因为 += 连接但之后没有使用。 这看起来像是通过引用传递,但实际上传递的是指向对象的指针的值。我能找到的最好的解释是 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

在第一种情况下,您创建了一个新对象 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"

"<<" is a Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand.

因此“<<”不会创建新字符串,str.contact("World") 也不会创建新字符串。 方法test1不需要对返回结果做任何处理,你可以试试这个方法:

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

I understand ruby does pass by reference for function parameters

Ruby 始终严格按值传递。 Ruby 中没有传递引用。

This is simply out of curiosity -- any explanations would be appreciated

为什么您的代码片段没有显示您期望的传递引用结果的简单解释是 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这样的纯函数式语言或清洁。

STRING 被引用,在 ruby 中除了像数字 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)