使用instance_eval初始化Ruby对象

时间:2018-03-14 10:10:27

标签: ruby initialization block

考虑以下课程:

class Person
    attr_accessor :first_name

    def initialize(&block)
        instance_eval(&block) if block_given?
    end
end

当我按如下方式创建Person的实例时:

person = Person.new do
    first_name = "Adam"
end

我期待以下内容:

puts person.first_name

输出" Adam"。相反,它只输出一个空行:first_name属性最终的值为nil。

当我创建一个喜欢这个的人时,不过:

person = Person.new do
    @first_name = "Adam"
end

first_name属性设置为期望值。

问题是我想在初始化块中使用attr_accessor,而不是直接使用属性。可以这样做吗?

4 个答案:

答案 0 :(得分:3)

如果代码在启用警告的情况下运行(即ruby -w yourprogram.rb) 它响应:"警告:已分配但未使用的变量 - first_name",其中行号指向first_name = "Adam"。所以Ruby将first_name解释为变量,而不是方法。正如其他人所说,使用明确的接收者:self.first_name

答案 1 :(得分:2)

如果没有显式接收器,则无法调用Ruby setter,因为局部变量优先于方法调用。

您不需要尝试这样一个过于复杂的示例,以下内容也不会起作用:

class Person
  attr_accessor :name
  def set_name(new_name)
    name = new_name
  end
end

只会这样:

class Person
  attr_accessor :name
  def set_name(new_name)
    # name = new_name does not call `#name=`
    self.name = new_name
  end
end

对于您的示例,您必须在接收器上显式调用该方法:

person = Person.new do
  self.first_name = "Adam"
end

答案 2 :(得分:0)

试试这个:

person = Person.new do |obj|
  obj.first_name = "Adam"
end

puts person.first_name

答案 3 :(得分:0)

  

我想在初始化块中使用attr_accessor,而不是直接使用属性

instance_eval破坏了封装。它为块提供了对实例变量和私有方法的访问。

考虑将person实例传递到块中:

class Person
  attr_accessor :first_name

  def initialize
    yield(self) if block_given?
  end
end

用法:

adam = Person.new do |p|
  p.first_name = 'Adam'
end
#=> #<Person:0x00007fb46d093bb0 @first_name="Adam">