假设我有一个简单的对象。对于我想接受的属性,我有attr_accessor
个,我希望能够使用对象的哈希进行初始化:
class Example
attr_accessor :foo, :bar
def initialize( attributes = {} )
attributes.each do |k,v|
...
end
end
end
在上面的attributes.each块中,最好使用send
,如下所示:
send "#{k}=", v
或使用instance_variable_set
,如下:
instance_variable_set "@#{k}".to_sym, v
......还是完全做其他事情?
我能想到的差异是:
如果在某些时候我使用setter方法替换send
中的一个,那么使用attr_accessors
会更加一致。
如果传递了意外的值,则使用send
会引发NoMethodError
由于这些原因,我倾向于send
- 我实际上有点像NoMethodError
因伪造的初始数据被提出的可能性。但是,我在这里忽略了其他任何因素,尤其是性能和安全方面的考虑因素吗?
我很欣赏任何见解。谢谢!
答案 0 :(得分:5)
我的回答是使用发送。
原因:即使访问者不存在,也会使用instance_variable_set创建实例变量。正如您所提到的,使用send,您将获得NoMethodError。
答案 1 :(得分:2)
您可以使用try
代替send
。如果找不到该方法,send
将返回NoMethod错误,如果找不到方法,try
将返回 nil 。 try
不能用于实例方法。
示例:强>
# k is a string or symbol, v a parameter value
try(k)
#=> nil
try(k, v)
#=> nil
但应使用方法instance_variable_set
和instance_variable_get
示例强>
# k is a string or symbol, v a value
instance_variable_set("@#{k}", v)
instance_variable_get("@#{k}")
答案 2 :(得分:1)
通常的做法是使用发送。
首先,instance_variable_set
将创建许多额外的实例变量。
然后,send使用访问器方法。当其中一个attr访问器被重新定义时非常有用,例如:
attr_accessor :foo
def bar=
# something's happening here
end
为了避免NoMethodError
,您应该使用respond_to?
方法:
attributes.each do |k, v|
send("#{k}=", v) if respond_to?(k)
end
在手动初始化或使用宝石之前,也可以裁剪额外的属性,例如: gem 'strong_parameters'