所以我发现了这种红宝石行为,让我疯狂了一个多小时。当我将哈希传递给具有哈希值和关键字参数的默认值的函数时,似乎引用没有被正确传递。只要我删除默认值OR关键字参数,该函数就会按预期运行。我在这里错过了一些明显的红宝石规则吗?
def change_hash(h={}, rand: om)
h['hey'] = true
end
k = {}
change_hash(k)
k
#=> {}
一旦取出默认值或关键字arg,它就可以正常工作。
def change_hash(h, rand: om)
h['hey'] = true
end
k = {}
change_hash(k)
k
#=> {'hey' => true}
def change_hash(h={})
h['hey'] = true
end
k = {}
change_hash(k)
k
#=> {'hey' => true}
感谢您的回答。大多数人都指出ruby在某些情况下会将哈希解析为关键字参数。但是,我在谈论哈希有字符串键的情况。当我传递哈希时,似乎传递的值是正确的。但是修改函数内的哈希并不会修改原始哈希。
def change_hash(hash={}, another_arg: 300)
puts "another_arg: #{another_arg}"
puts "hash: #{hash}"
hash['hey'] = 3
end
my_hash = {"o" => 3}
change_hash(my_hash)
puts my_hash
打印
another_arg: 300
hash: {"o"=>3}
{"o"=>3}
答案 0 :(得分:3)
TL; DR ruby允许传递散列作为关键字参数以及“扩展的inplace散列”。由于change_hash(rand: :om)
必须路由到关键字参数,因此change_hash({rand: :om})
也应如此因此,change_hash({})
。
由于ruby允许在任何位置使用默认参数,因此解析器首先处理默认参数。这意味着,默认参数是贪婪的,并且大多数默认值将占据一席之地。
另一方面,由于ruby缺少函数子句的模式匹配功能,因此解析给定参数以决定是否应将其作为double-splat传递会导致巨大的性能损失。由于使用显式关键字参数(change_hash(rand: :om)
)的调用应该明确地将:om
传递给关键字参数,而允许我们将显式哈希{rand: :om}
传递为关键字参数,Ruby无需接受任何哈希作为关键字参数。
Ruby将在hash
和rand
之间拆分单个哈希参数:
k = {"a" => 42, rand: 42}
def change_hash(h={}, rand: :om)
h[:foo] = 42
puts h.inspect
end
change_hash(k);
puts k.inspect
#⇒ {"a"=>42, :foo=>42}
#⇒ {"a"=>42, :rand=>42}
该分割功能要求在传递之前将参数克隆。这就是原始哈希没有被修改的原因。
答案 1 :(得分:0)
这确实是Ruby中特别棘手的情况。
在您的示例中,您有可选参数这是一个哈希,并且您同时拥有可选关键字参数。在这种情况下,如果只传递一个哈希值,Ruby会将其解释为包含关键字参数的哈希值。以下是澄清的代码:
change_hash({rand1: 'om'})
# ArgumentError: unknown keyword: rand1
要解决此问题,您可以将两个单独的哈希值传递给方法,第二个哈希值(关键字参数的哈希值)为空:
def change_hash(h={}, rand: 'om')
h['hey'] = true
end
k = {}
change_hash(k, {})
k
#=> {'hey' => true}
从实际的角度来看,最好避免像生产代码中那样使用metdhod签名,因为在使用该方法时很容易出错。