【问题标题】:why there are class variables in ruby?为什么ruby中有类变量?
【发布时间】:2011-07-14 13:01:32
【问题描述】:

如果创建类变量通常是危险且不可预测的,为什么我们需要它们? 如果解决方案只是将类实例变量与类级别访问器一起使用:

class Foo
  @variable = :something

  def self.getvariable
    @variable
  end

  def self.setvariable(value)
    @variable = value
  end
end

那我们为什么需要类变量???

【问题讨论】:

  • 为什么会“危险且不可预测”?
  • 因为所有类变量都可以在所有继承树中访问 => 它们可以被子类修改。看这里sporkmonger.com/2007/2/19/…
  • 如果您有类层次结构并且需要在某个层次结构树中的类之间共享一些数据,则需要类变量。
  • taro,所以,我们应该只在子类中像常量一样使用它们,而不是修改它们的值?
  • @Sergey 这并不会使它们“危险且不可预测”。它们非常可预测,只是不是类级别的实例变量

标签: ruby language-design class-variables


【解决方案1】:

类变量有时会用到,但我同意使用 eigenclass 通常更有用:

class Foo
  @bar = 'bar'
  class << self
    attr_accessor :bar
  end
end

puts Foo.bar         # bar
puts Foo.bar = 'baz' # baz

上面的继承是安全的,因为它在 Foo 常量中设置了一个变量,而不是一个类变量。

Foo.new.instance_eval { puts @@bar } # error

【讨论】:

  • 感谢您的意见,但我想看看您在说什么场合,因为对我来说,我认为类变量 - 在 Ruby 中是一件奇怪的事情
  • 我没有说它们不奇怪。只是,当您希望树中的所有类共享一些数据时,它们很方便。
【解决方案2】:

这有几个原因:

  1. 它是语法糖。您始终可以使用@@var 获取类变量(无论您是在类范围内还是在实例范围内)。这不适用于类的实例变量。

  2. 类变量对于此类实例的单例类保持不变。示例:

    class Test
    
      @instance_var = 0
      @@class_var = 0
    
      def self.instance_var
        @instance_var
      end
    
      def self.class_var
        @@class_var
      end
    
    end
    
    Test.instance_var #=> 0
    Test.class_var #=> 0
    Test.new.singleton_class.instance_var #=> nil
    Test.new.singleton_class.class_var #=> 0
    

【讨论】:

    【解决方案3】:

    这是一个例子(想想 ActiveRecord):

    class Base
      def connect(connection)
        @@connection = connection
      end
    
      def connection
        @@connection
      end
    end
    
    class User < Base
    end
    
    class SuperUser < User
    end
    
    Base.new.connect("A connection")
    puts User.new.connection      #=> A connection
    puts SuperUser.new.connection #=> A connection
    

    这里的诀窍是类变量可以从实例方法访问并被继承。试试这个:

    class Base
      def self.connect(connection)
        @connection = connection
      end
    
      def self.connection
        @connection
      end
    
      def connection
        self.class.connection
      end
    end
    
    class User < Base
    end
    
    Base.connect("A connection")
    puts User.new.connection #=> nil
    

    self.connection 尝试访问它自己的类实例变量(来自User 类)时,您将获得nil,并且它没有被继承。

    补充:是的,如果你滥用它可能会很危险:

    @@a = "A"
    
    class A
      def self.a
        @@a
      end
      def a
        @@a
      end
    end
    
    puts A.a     #=> A
    puts A.new.a #=> A
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      • 2014-06-19
      • 2013-02-05
      • 2014-09-20
      • 2012-09-22
      • 1970-01-01
      • 2017-04-10
      相关资源
      最近更新 更多