Ruby函数未显式return时,为何返回原数组而非预期nil?
问题背景
这段代码的设计目标是遍历传入的哈希数组:如果数组中哈希的指定key对应值不是nil,就将该值从JSON格式字符串转换为键为Symbol类型的Ruby哈希对象,示例1的运行结果符合预期。
示例2传入的key是数组中哈希都不存在的:key_4,因此if !hash[key].nil?的判断始终不成立,分支内逻辑完全没有执行。和预期中函数返回nil的认知不同,示例2实际返回了原数组data_2本身。核心疑问是:该场景下函数内最后一条被求值的语句到底是什么?
相关代码
方法定义:
require 'json' def convert(arr_of_hashes, key) arr_of_hashes.each do |hash| if !hash[key].nil? begin JSON.parse(hash[key]) rescue JSON::ParserError => e raise "Bad" else hash[key] = JSON.parse(hash[key], {:symbolize_names => true}) end end end end
测试用例:
data_1 = [ { :key_1 => "Apple", :key_2 => "{\"one\":1, \"two\":2}", :key_3 => 200 }, { :key_1 => "Orange" } ] data_2 = [ { :key_1 => "Apple", :key_2 => nil, :key_3 => 200 }, { :key_1 => "Orange" } ] # 示例1运行 p convert(data_1, :key_2) # 输出: [{:key_1=>"Apple", :key_2=>{:one=>1, :two=>2}, :key_3=>200}, {:key_1=>"Orange"}] # 示例2运行 p convert(data_2, :key_4) # 输出: [{:key_1=>"Apple", :key_2=>nil, :key_3=>200}, {:key_1=>"Orange"}]
解答
示例2场景下,函数最后一条被求值的语句是arr_of_hashes.each do ... end整个迭代调用表达式。
Ruby中Array#each的核心特性是:无论块内执行什么逻辑、是否进入条件分支,each方法遍历完所有元素后,永远返回调用它的原对象(即方法接收者)。
产生“应该返回nil”的认知偏差,是因为误将块内条件判断不成立的结果当成了整个迭代方法的返回值:
- 示例2遍历每个哈希时,块内只执行了
if !hash[key].nil?这行判断,求值结果为false,但each方法不会使用块的返回值,块的求值结果不影响each本身的返回逻辑。 - 哪怕是示例1的场景,
convert方法的返回值也不是分支内JSON解析的结果,同样是each返回的原数组。示例1中能看到哈希值被修改,是因为Ruby中哈希是可变对象,块内的赋值操作直接修改了原数组内存储的哈希对象,并非方法返回了新构造的数组。
内容的提问来源于stack exchange,提问作者Dante
相关产品推荐
相关产品推荐

