应该很容易,但我找不到合适的解决方案。 对于第一级键:
resource.public_send("#{key}=", value)
但foo.bar.lolo
?
我知道我可以像下面那样得到它:
'foo.bar.lolo'.split('.').inject(resource, :send)
或
resource.instance_eval("foo.bar.lolo")
但是如何将值设置为最后一个变量,假设我不知道嵌套级别,它可能是第二个或第三个。
是否有一般方法可以为所有级别执行此操作? 对于我的例子,我可以像下面这样做:
resource.public_send("fofo").public_send("bar").public_send("lolo=", value)
答案 0 :(得分:3)
出于好奇而回答哈希:
hash = { a: { b: { c: 1 } } }
def deep_set(hash, value, *keys)
keys[0...-1].inject(hash) do |acc, h|
acc.public_send(:[], h)
end.public_send(:[]=, keys.last, value)
end
deep_set(hash, 42, :a, :b, :c)
#⇒ 42
hash
#⇒ { a: { b: { c: 42 } } }
答案 1 :(得分:0)
ruby中的哈希默认情况下不会给你这些点方法。
你可以链接发送调用(这适用于任何对象,但通常不能以这种方式访问哈希键):
"foo".send(:downcase).send(:upcase)
使用嵌套哈希时,可变性的棘手概念是相关的。例如:
hash = { a: { b: { c: 1 } } }
nested = hash[:a][:b]
nested[:b] = 2
hash
# => { a: { b: { c: 2 } }
“Mutability”在这里意味着当您将嵌套哈希存储到单独的变量中时,它实际上仍然是指向原始哈希的指针。可变性对于这种情况很有用,但如果您不理解它也可能会产生错误。
您可以为变量指定:a
或:b
,使其在某种意义上具有“动态”。
有更多高级方法可以做到这一点,例如新版Ruby中的dig
versions.
hash = { a: { b: { c: 1 } } }
keys_to_get_nested_hash = [:a, :b]
nested_hash = hash.dig *keys_to_get_nested_hash
nested_hash[:c] = 2
hash
# => { a: { b: { c: 2 } } }
如果你使用OpenStruct
,那么你可以给你的哈希点方法访问器。老实说,链接send
电话不是我经常使用的。如果它可以帮助您编写代码,那就太棒了。但是你不应该发送用户生成的输入,因为它是不安全的。
答案 2 :(得分:0)
虽然您可以实施某些方法来按现在的方式设置它们,但我强烈建议您重新考虑数据结构。
为了澄清您的一些术语,示例中的key
不是键,而是方法调用。在Ruby中,当你有像my_thing.my_other_thing
这样的代码时,my_other_thing总是一种方法,而且永远不是一个密钥,至少不是正确的术语。
你可以通过这种方式链接对象来创建一个类似哈希的结构,但这有一个真正的代码味道。如果您认为foo.bar.lolo
是一种在哈希中查找嵌套lolo
键的方法,那么您应该使用常规哈希。
x = {foo: {bar: 'lolo'}}
x[:foo][:bar] # => 'lolo'
x[:foo][:bar] = 'new_value' # => 'new_value'
此外,虽然send / instance_eval方法可以这种方式使用,但这不是最佳做法,甚至可能会产生安全问题。