为什么在 Ruby 中嵌套 .map 方法对我来说表现得很奇怪?

Why Nesting .map method in Ruby behaves strange for my case?

也许这样做并不常见,但无论如何。我很好奇为什么它不起作用。 我遇到了一个我不完全理解的奇怪行为。

string = "sdsdasda asdas asdas"
words = string.split

words.map! do |word|
    word.split(//).map! do |character|
        character.upcase #or any other operations that change character
    end.join
end

p words.join(" ")

如果我不是奇数"end.join"构造这个

    end
    word.join
end

我得到一个错误,因为 |word|保持不变(字符串而不是大写),尽管使用

.map!

带感叹号。 所以基本上我的问题是为什么映射!不会改字的。

.map! 正在根据 .split(//) 的结果调用。它正在修改结果数组,而不是原来的 word

你可以想到把.split(//)的结果放在一个新的变量中:

characters = word.split(//)
characters.map! do |character|
  character.upcase
end

return characters.join
# `word` is not modified

代码块中的最后一行代码决定了 returned 到上一个循环的值。

通过将 .join 添加到 end,您实际上是在说您想要 return 该代码块的结果到之前的 map! 调用。但是,当您之后添加一行以显式执行 word.join 时,您就是在说您想要 return word.join 的结果到前一个 map! 调用。正如 Leny Sirivong 指出的那样,word 仍然是小写字母(您可以通过打印 word 来确认)。

考虑这个替代语法以使其更清晰:

string = "sdsdasda asdas asdas"
words = string.split

words.map! do |word|
    result = word.split(//).map! {|character|character.upcase }.join
    p "word: " + word
    p "result: " + result
end

p words.join(" ")

你会在这里看到它确实有效,因为我将循环的结果分配给一个新变量 result。然后,result 被传递回原始 map! 调用而不是 word

"word: sdsdasda"
"result: SDSDASDA"
"word: asdas"
"result: ASDAS"
"word: asdas"
"result: ASDAS"

如果你运行这个你会看到在这种情况下最终结果打印["result: SDSDASDA", "result: ASDAS", "result: ASDAS"]。那是因为我循环的最后一行是 p "result: " + result.