我看到了在 Ruby 中使用类变量的问题;然而,似乎 RuboCop 的关于如何解决这个问题的文档是不够的。
现在,我可以忽略它。鉴于我的项目,没关系。但是,我只想知道 Rubocop 试图告诉我做什么,因为它没有意义。
在with 中执行提供的代码给出:irb 0.9.6Ruby 2.5.1
class A
  @test = 10
end
#=> 10
class A
  def test
    @@test # you can access class variable without offense
  end
end
#=> :test
A.new.test
Traceback (most recent call last):
        3: from /Users/Ricky/.rbenv/versions/2.5.1/bin/irb:11:in `<main>'
        2: from (irb):12
        1: from (irb):9:in `test'
NameError (uninitialized class variable @@test in A)
Did you mean?  @test
所以不行。我们显然不能在没有冒犯的情况下访问类变量。irb非常生气。但是,ruby 建议使用@test. 也许这只是一个错字?让我们试试看:
class A
  @test = 10
  def test
    @test # you can access class variable without offense
  end
end
#=> :test
A.new.test
#=> nil
因此,从未定义实例变量。RuboCop 在这里想说什么?
Ale*_*kin 10
您错过了变量范围之间的差异。
class A
  @test = 42
end
上面在类范围内声明了一个实例变量。它可以作为
A.instance_variable_get(:@test)
#? 42
您可以为此变量定义访问器:
class A
  @test = 42
  def self.test
    @test
  end
end
A.test #? 42
它在实例之间共享,要从实例访问它,您应该引用该类:
#     ????? HERE
A.new.class.test #? 42
以下代码在类实例上声明了一个实例变量:
class A
  def initialize
    @test = 42
  end
end
它可以从访问情况的A:
A.new.instance_variable_get(:@test)
#? 42
在类层次结构中使用类变量时,类变量有一些缺点,这 [可能] 这就是为什么 Rubocop 建议不要使用类变量(或它建议的任何内容——老实说,我从未使用过它,因为它带来的危害大于帮助 IMSO。)
在您的第一个片段中,您错过了@. 正确的代码是:
class A
# ?? HERE
  @@test = 10
end
class A
  def test
    @@test # you can access class variable without offense
  end
end
小智 7
2023 年初,这个问题仍然存在。因为 rubocop 文档不是发布有关 ruby 中 OOP 复杂性的信息的地方。
不喜欢使用类变量来自于我们使用类继承时的意外行为。但我们喜欢看代码,而不是阅读描述,文档中明确指出:
为类变量设置值时必须小心;如果一个类被继承,改变类变量的值也会影响继承的类。这意味着使用类实例变量几乎总是更好。
我想补充 Alexey Matyushkin 的答案,并用简单的例子展示类变量的行为。并解释这会导致什么。
我确认 rubocop 文档中的代码是某种废话:
# good
class A
  @test = 10
end
class A
  def test
    @@test # you can access class variable without offense
  end
end
class A
  def self.test(name)
    class_variable_get("@@#{name}") # you can access without offense
  end
end
begin
  puts A.new.test
rescue => e
  puts e.message
end
begin
  puts A.test 'test'
rescue => e
  puts e.message
end
puts "RUBY_VERSION: #{RUBY_VERSION}"
=>>>
uninitialized class variable @@test in A
Did you mean?  @test
uninitialized class variable @@test in A
Did you mean?  @test
RUBY_VERSION: 2.5.3
uninitialized class variable @@test in A
Did you mean?  @test
uninitialized class variable @@test in A
Did you mean?  @test
RUBY_VERSION: 2.5.3
=>>>
When we use "classic" class variables:
10
- the child class has inherited the methods and the value of the variable.
20
- but the variable of the parent class was implicitly changed (bad)!
When we use class instance variables:
- the child class has inherited the methods, but not the value of the variable (this is also bad)!
10
- a change in the child class does not lead to a change in the parent.
修改大型程序的一种方法是继承该类并对其进行自己的更改。通常项目很复杂,有很多隐式依赖关系(说实话=)),如果直接对类进行更改,项目就会崩溃。因此,我们使用继承,子类在一个新的服务中使用它自己的设置,或者子类改变程序某一部分的行为。而如果在继承过程中,子类突然改变了基类,那么继承就失去了意义!灵活性丧失了。
但任何问题都需要结合上下文来看待。如果你单独写一个微型项目,那么@@ var 并没有什么问题。你只需要理解。