为什么Ruby中的双铲不会改变状态?

squ*_*ism 12 ruby string

我遇到了这种引起错误或混乱的奇怪副作用.所以,想象一下,这不是一个简单的例子,但的一个例子疑难杂症可能.

name = "Zorg"

def say_hello(name)
  greeting = "Hi there, " << name << "?"
  puts greeting
end

say_hello(name)
puts name

# Hi there, Zorg?
# Zorg
Run Code Online (Sandbox Code Playgroud)

这不会改变名称.名字还在Zorg.

但现在看一个非常微妙的区别.在下一个例子中:

name = "Zorg"

def say_hello(name)
  greeting = name << "?"
  puts "Hi there, #{greeting}"
end

say_hello(name)
puts name

# Hi there, Zorg?
# Zorg?  <-- name has mutated
Run Code Online (Sandbox Code Playgroud)

现在名字是Zorg?.疯.greeting =任务中的细微差别.Ruby在内部使用解析(?)或消息传递链接?我以为这只会像铲子一样链起来name.<<("?"),但我想这不会发生.

这就是为什么我在尝试连接时避免使用铲子操作符的原因.我一般尽量避免变异状态,但Ruby(目前)尚未针对此进行优化(尚未).也许Ruby 3会改变一切.很抱歉有关Ruby未来的范围 - 蠕变/侧面讨论.

我认为这特别奇怪,因为具有较少副作用的示例(第一个)具有两个铲操作符,其中具有更多副作用的示例具有更少的铲操作符.

更新 你是正确的DigitalRoss,我让它太复杂了.减少的例子:

one = "1"
two = "2"
three = "3"
message = one << two << three
Run Code Online (Sandbox Code Playgroud)

那你认为一切都是什么?(没有偷看!)如果我不得不猜测我会说:

one is 123
two is 23
three is 3
message is 123
Run Code Online (Sandbox Code Playgroud)

但我两个人都错了.二是2.

mu *_*ort 9

如果我们将你的a << b << c构造转换为更多的方法形式并抛出一堆隐含的括号,那么行为应该更清晰.重写:

greeting = "Hi there, " << name << "?"
Run Code Online (Sandbox Code Playgroud)

收益率:

greeting = ("Hi there, ".<<(name)).<<("?")
Run Code Online (Sandbox Code Playgroud)

String#<<正在修改的东西,但name永远不会作为目标/ LHS出现<<,"Hi there ," << name字符串会但name不会.如果用变量替换第一个字符串文字:

hi_there = 'Hi there, '
greeting = hi_there << name << '?'
puts hi_there
Run Code Online (Sandbox Code Playgroud)

你会看到<<改变了hi_there; 在你的"Hi there, "情况下,这个更改是隐藏的,因为你正在修改一些你以后无法看到的东西(一个字符串文字).