【问题标题】:Ruby dynamic object attributes, send vs instance variable setRuby 动态对象属性,发送 vs 实例变量集
【发布时间】:2013-02-04 21:50:06
【问题描述】:

假设我有一个简单的对象。我有attr_accessors 用于我想要接受的属性,并且我希望能够使用对象哈希进行初始化:

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

...还是完全做其他事情?

我能想到的区别是:

  • 如果在某个时候我将其中一个attr_accessors 替换为setter 方法,那么使用send 会更加一致。

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

出于这些原因,我倾向于send —— 实际上,我有点喜欢NoMethodError 被提出用于伪造初始化数据的可能性。但是,我在这里是否忽略了其他任何因素,尤其是性能和安全方面的考虑?

我感谢任何见解。谢谢!

【问题讨论】:

  • 我会使用send,除非我有充分的理由不这样做;作为一般规则,我更喜欢我的对象在与自己对话时使用外部接口,这样可以减少维护麻烦。顺便说一句,如果您不想要明确的 to_sym 呼叫,您可以说 :"@#{k}"。
  • @muistooshort:感谢:"" 的提示,不知道!

标签: ruby metaprogramming


【解决方案1】:

我的回答是使用发送。

原因:即使访问器不存在,也会使用 instance_variable_set 创建实例变量。正如你所提到的,使用 send 你会得到一个 NoMethodError。

【讨论】:

    【解决方案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}")
    

    【讨论】:

      【解决方案3】:

      通常的做法是使用发送。

      首先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
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-11
        • 2012-05-14
        • 2012-05-18
        • 2017-05-23
        • 2011-10-08
        • 1970-01-01
        • 2021-10-25
        相关资源
        最近更新 更多