为什么Ruby中有类变量?

3
如果创建类变量经常是危险和不可预测的,那么为什么我们需要它们呢?如果解决方案只是使用具有类级别访问器的类实例变量:
class Foo
  @variable = :something

  def self.getvariable
    @variable
  end

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

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

3
为什么它是“危险和不可预测的”? - Draco Ater
如果你有类层次结构并且需要在某些层次树中的类之间共享一些数据,那么你就需要类变量。 - taro
所以,taro和so应该只在子类中作为常量使用,而不修改它们的值? - Sergey
Sergey,我真的不明白你的观点。这在面向对象编程中是完全可以接受的。 - Candide
2
@Sergey,这并不意味着它们是“危险和不可预测的”。它们非常可预测,只是它们不是类级实例变量。 - Gareth
显示剩余4条评论
3个回答

1

这有几个原因:

  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
    

1

类变量有时会有用,但我同意使用特殊类更常见:

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中类变量是一件奇怪的事情。 - Sergey
我并没有说它们不奇怪。只是当你想让树中的所有类共享一些数据时,它们很方便。 - Denis de Bernardy

0
这是一个例子(类似 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接