在Ruby中的类范围中使用@variable是正确的吗?

时间:2014-05-06 10:06:50

标签: ruby

我看到ruby项目在ruby类的类范围内使用实例变量@var。

我认为在类方法中,应该使用类变量@@ var,并且在实例方法中,使用实例变量@var。

我想在类范围内使用@var是正确的方法吗?

目前我知道在类范围中使用实例变量和类变量之间的区别在于实例变量不能由子类继承。代码演示了这种干扰。

class Foo
  @bar = 8
  @@bar2 = 10
  def self.echo_bar
    p @bar
  end

  def self.echo_bar2
    p @@bar2
  end
end

class Foo2 < Foo

end

Foo.echo_bar
Foo.echo_bar2

Foo2.echo_bar
Foo2.echo_bar2
# Result:
# 8
# 10
# nil
# 10

2 个答案:

答案 0 :(得分:3)

Ruby对象是:

  1. 数据 - 实例变量的映射和关联的值。请注意,实例变量对于实例本身是私有的。
  2. Behavior - 定义指向此实例响应的方法的类的指针。注意方法可以从父类继承。
  3. Class是Ruby中的一个对象。写下:

    class Foo
      @bar = 8
      def self.get_bar
        @bar
      end
    end
    

    您获得了以下数据模型(不完全是,Foo的祖先及其特征类的层次结构已被删除):

                                 Class
                                   |
    Foo        class ptr    [eigenclass of Foo]
    @bar = 8   --------->   method - get_bar 
    

    类范围的实例变量定义该类对象的私有数据。从上面的模型中,可以通过Foo的本征类中定义的实例方法以及其祖先链Class, Module, Object, Kernel, BasicObject访问此实例变量。这些实例变量定义了与类对象Foo相关联的一些数据。

    写作:

    class FooChild < Foo
    end
    

    你有

                                 Class
                                   |
    Foo         class ptr    [eigenclass of Foo]
    @bar = 8    --------->   method - get_bar
        |                          |
    FooChild    class ptr    [eigenclass of FooChild]
    <Nothing>   --------->   <Nothing>
    

    类对象FooChildget_bar的特征类继承方法Foo,因此您可以调用FooChild.get_bar。但是,由于接收方为FooChild,并且没有实例变量@barFooChild相关联,因此将返回默认值nil

    上述分析在Meta-programming Ruby一书中更详细。

    类变量(@@bar2),IMO是一个带有奇怪解析顺序的范围变量。通过在@@bar2的类范围中引用Foo,它将在Foo的祖先链中查找@@bar2的定义, FROM TOP TO BOTTOM 即可。因此,它首先会在BasicObject,然后Kernel,然后是Object,最后是Foo进行查询。

    玩下面的例子:

    class Foo
      @@bar = 1
      def self.show
        puts @@bar
      end
    end
    
    Foo.show  #=> 1
    
    class Object
      @@bar = "hahaha"
    end
    
    Foo.show  #=> hahaha
    

答案 1 :(得分:0)

在类中定义的实例变量,但在名为class instance variable的实例方法之外。

使用类实例变量与类变量的优点是使用继承。您也可以在子类中使用类实例变量,但它看起来很混乱。

它不完全是一种继承。 Ruby实现有点棘手。 Ruby中的实例变量是在值赋值发生时创建的。

任何子类都可以更改共享类变量的值,但只为特定类创建类实例变量。因此,请注意您班级中变量所需的行为。

与类变量相比,类实例变量的缺点是它们不能在实例方法中使用。除此之外,您还可以将它们与常规实例变量混淆。

  class Foo
    @class_instance_var_1 = 0
    @class_instance_var_2 = 0
    @@class_var = 10

    def initialize
      @class_instance_var_1 = 1 # cannot change it here
      @@class_var = 100
    end

    def self.change
      @class_instance_var_2 = 2 # can change here
      @@class_var = 200
    end

    def self.echo_var
      p 'class_instance_var_1=' + @class_instance_var_1.to_s
      p 'class_instance_var_2=' + @class_instance_var_2.to_s
      p 'class_var=' + @@class_var.to_s
    end
  end

  puts '--- initial status of Foo'
  Foo.echo_var
  puts '--- initialized Foo'
  Foo.new
  Foo.echo_var
  puts '--- changed Foo'
  Foo.change
  Foo.echo_var

  class Foo2 < Foo
    @class_instance_var_2 = 22 # can set here only but not in Foo
    @@class_var = 20 # can change here and everywhere
  end

  puts '--- after Foo2 implementation'
  puts '--- Foo'
  Foo.echo_var
  puts '--- Foo2'
  Foo2.echo_var

  class Foo3 < Foo2
    @class_instance_var_2 = 33 # can set here only but not in Foo
    @@class_var = 30 # can change here and everywhere
  end

  puts '--- after Foo3 implementation'
  puts '--- Foo'
  Foo.echo_var
  puts '--- Foo2'
  Foo2.echo_var
  puts '--- Foo3'
  Foo3.echo_var

输出此

--- initial status of Foo
"class_instance_var_1=0"
"class_instance_var_2=0"
"class_var=10"
--- initialized Foo
"class_instance_var_1=0"
"class_instance_var_2=0"
"class_var=100"
--- changed Foo
"class_instance_var_1=0"
"class_instance_var_2=2"
"class_var=200"
--- after Foo2 implementation
--- Foo
"class_instance_var_1=0"
"class_instance_var_2=2"
"class_var=20"
--- Foo2
"class_instance_var_1="
"class_instance_var_2=22"
"class_var=20"
--- after Foo3 implementation
--- Foo
"class_instance_var_1=0"
"class_instance_var_2=2"
"class_var=30"
--- Foo2
"class_instance_var_1="
"class_instance_var_2=22"
"class_var=30"
--- Foo3
"class_instance_var_1="
"class_instance_var_2=33"
"class_var=30"