Ruby初学者疑问:为何.each块无法修改外部初始化变量?
解决Ruby块中无法修改/访问外部变量的问题
嗨,我来帮你把这个问题掰明白!你遇到的核心问题其实是Ruby的局部作用域规则,以及for循环和each迭代器之间的作用域差异。
先看你写的each版本代码为什么不行:
def longest_word(sentence) max_length = 0 sentence.split(" ").each do |word| if word.length > max_length max_length = word.length max_word = word # 这里的max_word是块的局部变量! end end return max_word # 外部访问不到块内的局部变量,会报错 end
在Ruby里,块会创建自己的局部作用域:如果你在块内给一个之前没在外部作用域定义过的变量赋值,这个变量就会变成块的局部变量——出了块之后,外部根本看不到它。所以你最后return的时候,max_word是未定义的,会抛出NameError。
而你用的for循环不一样:Ruby的for循环不会创建新的局部作用域,循环里赋值的max_word属于方法的作用域,所以在循环结束后依然能访问到。
那怎么用each实现和for循环一样的效果?很简单,提前在块外部初始化max_word,让它属于方法的作用域,这样块里赋值的就是这个外部变量了:
def longest_word(sentence) max_length = 0 max_word = nil # 提前初始化,把变量放到方法作用域里 sentence.split(" ").each do |word| if word.length > max_length max_length = word.length max_word = word # 现在修改的是外部的max_word end end return max_word end
这样修改后,each块里的赋值操作会直接修改方法作用域里的max_word,循环结束后就能正常返回结果了。
顺便说一句:你听说“Ruby中用for循环会引发严重bug”有点夸张了,for循环本身没问题,只是Ruby社区更推崇each这类迭代器——因为它们更符合Ruby的面向对象设计风格,而且链式调用更灵活。for循环本质上其实是调用each的语法糖,只是作用域规则和each不同而已。
另外你写的那种用map+max的写法确实很Rubyic,不过搞清楚作用域问题能帮你避开很多类似的坑,很棒!
内容的提问来源于stack exchange,提问作者TravisHN
相关产品推荐
相关产品推荐

