在 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
rubocop 真正想告诉我们什么。
puts 'When we use "classic" class variables:'
class A
@@var = 10
cattr_accessor :var
end
class Aa < A
end
puts Aa.var, '- the child class has inherited the methods and the value of the variable.'
Aa.var = 20
puts A.var, '- but the variable of the parent class was implicitly changed (bad)!'
puts 'When we use class instance variables:'
class B
@test = 10
class << self
attr_accessor :test
end
end
class Bb < B
end
puts Bb.test, '- the child class has inherited the methods, but not the value of the variable (this is also bad)!'
Bb.test = 20
puts B.test, '- a change in the child class does not lead to a change in the parent.'
=>>>
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.
有什么大不了的?这怎么可能有害?
修改 BIG 程序的一种方法是继承该类并对它进行自己的更改。通常项目很复杂,有很多隐含的依赖(说实话=)),如果直接对类进行更改,项目就会崩溃。因此,我们使用继承,将子类用于具有自己设置的新服务中,或者子类改变程序一部分的行为。如果在继承过程中,子类突然改变了基类,那么继承就失去了意义!失去了灵活性。
但是任何问题都需要在上下文中查看。如果你一个人在写一个微型项目,那么@@ var 没有任何问题。你只需要理解。