在Ruby中直接访问实例变量?

时间:2016-08-04 00:58:46

标签: ruby

为什么我不能使用ruby方法或accessor直接在instance_variable_get中访问实例变量?

class Foo
   @my_var
end

为什么我们不能在这个例子中使用Foo.@my_var

2 个答案:

答案 0 :(得分:2)

OP提供的示例是类实例变量。这些只能通过方法访问。

"定期"属性访问者不允许从课外访问。以下是创建有效的访问器的几种方法:

class A
    @class_instance_var = "foo"

    class << self
        attr_accessor :class_instance_var
    end

end

puts A::class_instance_var  # Output: foo

OR

class A
    @class_instance_var = "foo"

    def self.class_instance_var
      @class_instance_var
    end
end

puts A::class_instance_var  # Output: foo

类实例变量

类实例变量名也以@开头。但是,它们是在类级别定义的,不在任何方法之外。类实例变量只能通过类方法访问。它们在类的所有实例之间共享,但不在其子类之间共享。换句话说,它们不是可继承的。如果在类的一个实例中更改了类实例变量的值,则会影响所有其他实例。之前我们看到所有类都是一个名为Class的内置类的实例。这就是使类实例变量成为可能的原因。

class Vehicle
  @count = 0        # This is a class instance variable

  def initialize
    self.class.increment_count
    self.class.show_count
  end

  def self.increment_count    # This is a class method
    @count += 1
  end

  def self.show_count        # This is a class method
    puts @count
  end

end

class Car < Vehicle
  @count = 0
end

v1 = Vehicle.new    # Output: 1
v2 = Vehicle.new    # Output: 2
v3 = Vehicle.new    # Output: 3

car1 = Car.new        # Output: 1
car2 = Car.new        # Output: 2

v3 = Vehicle.new    # Output: 4

让我们回顾一下上面的例子。在Vehicle类中设置了一个名为@count的类实例变量,初始值为0.每次实例化Vehicle类时,initialize方法调用self.increment_count来增加@count的值,并使用self.show_count返回新的价值。然后,我们有Car类,它是Vehicle的子类,并继承了它的所有方法。但是,它不会继承@count类实例变量,因为这种类型的变量不可继承。这就是为什么计数器在Car类中起作用的原因,但它有自己的计数。

以self为前缀的方法,例如self.increment_count和self.show_count,是类方法。这是唯一能够访问类实例变量的方法。

答案 1 :(得分:1)

那不是语言的构建方式。也许看看openstruct

require 'ostruct'

obj = OpenStruct.new(my_var: 1)

obj.my_var
# => 1

顺便提一下,您设置实例变量的方法不正确。您应该只在实例方法或initialize中设置实例变量,否则使用类变量或常量。

使用常量的示例:

class Foo
   MyVar = 1
end

Foo::MyVar
# => 1

您还可以Foo.new.@my_var使用method_missing

class Foo
  def method_missing(m, *args, &block)  
    self.instance_variable_get(m)
  end
  def initialize
    @my_var = 1
  end
end

Foo.new.@my_var
# => 1