对发送方法设置实例变量感到困惑

时间:2013-11-14 06:14:54

标签: ruby

我有以下代码:

class Dog
  def initialize(attributes = {})
    attributes.each do |attr, value|
      send("#{attr}", value)
    end
  end
end


dog = Dog.new({:talk => 'bruuuf'})

我在初始化'得到一个块':未定义的方法`talk'for#(NoMethodError)

不发送应该做的事情:

dog.talk = bruuuf为什么不让我这样做?此外,这不会设置实例变量,但会创建实例方法。正确?

2 个答案:

答案 0 :(得分:1)

如果定义了方法talk,则可以执行send(:talk),但由于未定义talk,因此您无法执行此操作。此外,dog.send(:talk)不会给您dog.talk = bruuuf。如果talk=已定义,dog.send(:talk=, ...)将会执行此操作。

答案 1 :(得分:1)

首先关闭:您无法使用Object#send设置实例变量。 Object#send发送消息,它不设置实例变量。当然,您可以发送一条消息,该消息可能会或者可能不会再调用一个方法,该方法可能会或者可能不会依次设置实例变量,但这不是Object#send的操作,而是执行任何方法被调用以响应您发送的消息。

如果要动态设置实例变量,请使用Object#instance_variable_set

class Dog
  def initialize(**attrs)
    attrs.each do |attr, value|
      instance_variable_set(:"@#{attr}", value)
    end
  end
end

dog = Dog.new(talk: 'bruuuf')

但是,在这种情况下,看起来您实际上并不想设置实例变量,而是调用setter方法。 Setter方法的名称以=符号结尾,例如Dog#talk=

class Dog
  def initialize(**attrs)
    attrs.each do |attr, value|
      send(:"#{attr}=", value)
    end
  end
end

dog = Dog.new(talk: 'bruuuf')

当然,请注意,这假定方法Dog#talk=实际存在。如果没有,您将获得NoMethodError