您何时使用常量而不是类实例变量?它们都具有相同的范围。例子会有所帮助。
答案 0 :(得分:3)
考虑这个课程:
class Dog
NUMBER_OF_LEGS = 4
@dog_counter = 0
attr_reader :name
def initialize(name)
@name = name
end
def legs
NUMBER_OF_LEGS
end
end
此处,NUMBER_OF_LEGS
是常量,@name
是实例变量(使用getter方法),@dog_counter
是什么叫做类实例变量。
在Ruby中,一切都是对象,甚至是类,因此它们可以拥有自己的实例变量。
看看我们如何使用这个类:
dog = Dog.new('Chewbacca')
dog.name
# => 'Chewbacca'
dog.legs
# => 4
Dog::NUMBER_OF_LEGS
# => 4
没关系,但我们不拥有访问@dog_counter
的直接界面。使用内省方法的唯一方法是使用内省方法:
dog.class.instance_variable_get(:@dog_counter)
# => 0
dog.class.instance_variable_set(:@dog_counter, 1)
dog.class.instance_variable_get(:@dog_counter)
# => 1
dog.class.instance_eval { @dog_counter = 10 }
dog.class.instance_variable_get(:@dog_counter)
# => 10
我们可以做得更好。看看这个其他实现:
class Dog
@dog_counter = 0
attr_reader :name
class << self
attr_accessor :dog_counter
end
def initialize(name)
@name = name
self.class.dog_counter += 1
end
end
现在我们已经定义了一个类访问器(setter和getter),我们也在为每个新实例递增它。界面很简单:
Dog.dog_counter
# => 0
dog_1 = Dog.new('Han')
dog_2 = Dog.new('Luke')
Dog.dog_counter
# => 2
dog_2.class.dog_counter
# => 2
对于正确的类变量,它们在类上作用域,可以通过实例访问。
然而,最大的问题是它们在同一层次结构中的所有类之间共享。设置新值的每个类都将为其所有祖先和后代更新它。
出于这个原因,通常会避免使用它们,并且首选类实例变量(它们是特定于类的)。
class Scientist
@@greet = "Hello, I'm a Scientist!"
def greet
@@greet
end
end
class Biologist < Scientist
@@greet = "Hello, I'm a Biologist!"
end
class Physicist < Scientist
@@greet = "Hello, I'm a Physicist!"
end
class ParticlePhysicist < Physicist
@@greet = "Hello, I'm a ParticlePhysicist!"
end
biologist = Biologist.new
biologist.greet
# => "Hello, I'm a ParticlePhysicist!"
答案 1 :(得分:1)
他们没有相同的范围。类和它的实例引用相同的常量,但不是同一个实例变量,给定相同的名称。常量也可以从模块的命名空间引用,但实例变量不能。
如果要访问从类方法和实例方法或其他模块引用的内容,则需要一个常量。
你可以反对警告,但这并不好。当你有变化的东西时,最好使用一个变量。
答案 2 :(得分:0)
关于常量和具有相同范围的实例变量:
C = 10
class Dog
def initialize
puts C #=>10
@x = 1
puts @x #=>1
end
end
d = Dog.new
puts C #=>10
p @x #=>nil It sure doesn't look like @x has the same scope as C.
...
@x = 1
class Dog
C = 10
def initialize
puts C #=>10
p @x #=>nil Here @x does not have the same scope as C.
end
end
d = Dog.new
puts @x #=>1
puts C #=>Error uninitialized constant. Here C does not have the same scope as @x.
现在有些术语:
实例变量会在创建实例变量时将自身附加到self的任何对象上。
在召唤实例变量时,在任何自身对象中查找实例变量。
在initialize()中,Dog实例是self。在顶层,self是一个名为'main'的对象。这应该可以让你弄清楚上面的结果。
@variables将自己附加到实例,而方法将自身附加到类。同一个类的实例共享类中的方法,但类的实例不共享@变量 - 每个实例都有自己的@variables;两个实例甚至不必具有相同的@variables:
class Dog
attr_accessor :x, :y, :z
def initialize
end
end
d1 = Dog.new
d1.x = 10
d2 = Dog.new
d2.y = 1
d2.z = 2
p d1.instance_variables
p d2.instance_variables
--output:--
[:@x]
[:@y, :@z]
本地变量,例如'x','y'用于存储可以更改的值。
常量用于存储您不想更改的值。
@variables 用于将值附加到实例。如果你想让@variable保持不变,那就不要定义一个setter方法,虽然这不是万无一失的,因为ruby允许程序员在他们希望的时候侵犯隐私。