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

标签 ruby string

我遇到了导致错误或困惑的奇怪副作用。所以想象一下,这不是一个微不足道的例子,而是一个陷阱的例子。

name = "Zorg"

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

say_hello(name)
puts name

# Hi there, Zorg?
# Zorg

这不会改变名称。姓名仍为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

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

这就是为什么我在尝试进行串联时避免使用铲子运算符。我通常尽量避免改变状态,但 Ruby(目前)还没有为此进行优化(还)。也许 Ruby 3 会改变一切。对于关于 Ruby future 的范围蔓延/旁白讨论,我们深表歉意。

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

更新 你是对的 DigitalRoss,我把它弄得太复杂了。 简化示例:

one = "1"
two = "2"
three = "3"
message = one << two << three

现在你认为一切都准备好了? (不要偷看!) 如果非要我猜的话,我会说:

one is 123
two is 23
three is 3
message is 123

但我错了两个。二是 2。

最佳答案

如果我们转换您的 a << b << c构造成更像方法的形式并放入一堆隐式括号,行为应该更清晰。重写:

greeting = "Hi there, " << name << "?"

产量:

greeting = ("Hi there, ".<<(name)).<<("?")

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

hi_there = 'Hi there, '
greeting = hi_there << name << '?'
puts hi_there

你会看到 <<已更改 hi_there ;在你的"Hi there, "在这种情况下,此更改是隐藏的,因为您正在修改之后无法查看的内容(字符串文字)。

关于ruby - 为什么 Ruby 中的双铲不改变状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40877662/

相关文章:

ruby-on-rails - 使用 capistrano 将 Rails 部署到登台会生成以下错误

ruby - 阅读表格的一半

ruby - 如何创建和使用多态关系?

python - write() 与 writelines() 和连接字符串

java - 测试字符串是否包含数组中的任何字符串

python - 反转字符串顺序

ruby-on-rails - ImageMagick - "CORE_RL_magick_.dll not found"或如何使用 ruby​​ 1.9.2 在 Windows 上安装 RMagick

PHP - 将字符串转换为 float

r - 将重复值合二为一后连接两列的更好/更快的方法?

javascript - 如何制作可插入 JavaScript 文件的 Shopify 应用程序?