Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby动态对象属性,发送vs实例变量集_Ruby_Metaprogramming - Fatal编程技术网

Ruby动态对象属性,发送vs实例变量集

Ruby动态对象属性,发送vs实例变量集,ruby,metaprogramming,Ruby,Metaprogramming,假设我有一个简单的对象。我有attr\u访问器s用于我想要接受的属性,并且我想要能够使用对象的散列进行初始化: class Example attr_accessor :foo, :bar def initialize( attributes = {} ) attributes.each do |k,v| ... end end end 在上面的attributes.each块中,是否最好使用send,如下所示: send "#{k}=", v in

假设我有一个简单的对象。我有
attr\u访问器
s用于我想要接受的属性,并且我想要能够使用对象的散列进行初始化:

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 "@#{k}".to_sym, v
或者使用
实例变量集
,如下所示:

send "#{k}=", v
instance_variable_set "@#{k}".to_sym, v
。。。或者完全做别的事情

我能想到的区别是:

  • 如果在某个时候我用setter方法替换了一个
    attr\u访问器,那么使用
    send
    会更加一致

  • 如果传递了意外值,则使用
    send
    将引发
    NoMethodError

出于这些原因,我倾向于
send
——我实际上有点喜欢为伪造的init数据而提出
NoMethodError
。但是,这里是否还有其他我忽略的因素,特别是性能和安全方面的考虑


我很欣赏你的见解。谢谢

我的答案是使用send


原因:即使访问器不存在,也将使用实例变量集创建实例变量。正如您所提到的,使用send,您将获得一个命名错误。

您可以使用
try
而不是
send
<如果找不到方法,
send
将返回NoMethod错误,
try
如果找不到方法将返回nil<代码>尝试
不能用于实例方法

示例:

# k is a string or symbol, v a parameter value

try(k)
#=> nil

try(k, v)
#=> nil
但是,应该使用方法
instance\u variable\u set
instance\u variable\u get

示例

# k is a string or symbol, v a value
instance_variable_set("@#{k}", v)
instance_variable_get("@#{k}")

通常的做法是使用send

首先,
instance\u variable\u set
将创建大量额外的实例变量

然后,send使用accessor方法。当其中一个attr访问器被重新定义时,它非常有用,例如:

attr_accessor :foo

def bar=
  # something's happening here
end
为了避免出现
nomethoder错误
您应该使用
respond\u to?
方法:

attributes.each do |k, v|
  send("#{k}=", v) if respond_to?(k)
end

也可以在手动初始化或使用gems之前裁剪额外属性,例如
gem'strong_parameters'

我会使用
send
,除非我有很好的理由不这样做;一般来说,我更喜欢我的对象在与自己交谈时使用外部接口,这样可以减少维护的麻烦。顺便说一句,如果你不想显式地调用
,“@#{k}”
。@muistooshort:谢谢
:”
,我不知道!