我看到ruby项目在ruby类的类范围内使用实例变量@var。
我认为在类方法中,应该使用类变量@@ var,并且在实例方法中,使用实例变量@var。
我想在类范围内使用@var是正确的方法吗?
目前我知道在类范围中使用实例变量和类变量之间的区别在于实例变量不能由子类继承。代码演示了这种干扰。
class Foo
@bar = 8
@@bar2 = 10
def self.echo_bar
p @bar
end
def self.echo_bar2
p @@bar2
end
end
class Foo2 < Foo
end
Foo.echo_bar
Foo.echo_bar2
Foo2.echo_bar
Foo2.echo_bar2
# Result:
# 8
# 10
# nil
# 10
答案 0 :(得分:3)
Ruby对象是:
Class是Ruby中的一个对象。写下:
class Foo
@bar = 8
def self.get_bar
@bar
end
end
您获得了以下数据模型(不完全是,Foo的祖先及其特征类的层次结构已被删除):
Class
|
Foo class ptr [eigenclass of Foo]
@bar = 8 ---------> method - get_bar
类范围的实例变量定义该类对象的私有数据。从上面的模型中,可以通过Foo的本征类中定义的实例方法以及其祖先链Class, Module, Object, Kernel, BasicObject
访问此实例变量。这些实例变量定义了与类对象Foo
相关联的一些数据。
写作:
class FooChild < Foo
end
你有
Class
|
Foo class ptr [eigenclass of Foo]
@bar = 8 ---------> method - get_bar
| |
FooChild class ptr [eigenclass of FooChild]
<Nothing> ---------> <Nothing>
类对象FooChild
从get_bar
的特征类继承方法Foo
,因此您可以调用FooChild.get_bar
。但是,由于接收方为FooChild
,并且没有实例变量@bar
与FooChild
相关联,因此将返回默认值nil
。
上述分析在Meta-programming Ruby一书中更详细。
类变量(@@bar2
),IMO是一个带有奇怪解析顺序的范围变量。通过在@@bar2
的类范围中引用Foo
,它将在Foo
的祖先链中查找@@bar2
的定义, FROM TOP TO BOTTOM 即可。因此,它首先会在BasicObject
,然后Kernel
,然后是Object
,最后是Foo
进行查询。
玩下面的例子:
class Foo
@@bar = 1
def self.show
puts @@bar
end
end
Foo.show #=> 1
class Object
@@bar = "hahaha"
end
Foo.show #=> hahaha
答案 1 :(得分:0)
在类中定义的实例变量,但在名为class instance variable
的实例方法之外。
使用类实例变量与类变量的优点是使用继承。您也可以在子类中使用类实例变量,但它看起来很混乱。
它不完全是一种继承。 Ruby实现有点棘手。 Ruby中的实例变量是在值赋值发生时创建的。
任何子类都可以更改共享类变量的值,但只为特定类创建类实例变量。因此,请注意您班级中变量所需的行为。
与类变量相比,类实例变量的缺点是它们不能在实例方法中使用。除此之外,您还可以将它们与常规实例变量混淆。
class Foo
@class_instance_var_1 = 0
@class_instance_var_2 = 0
@@class_var = 10
def initialize
@class_instance_var_1 = 1 # cannot change it here
@@class_var = 100
end
def self.change
@class_instance_var_2 = 2 # can change here
@@class_var = 200
end
def self.echo_var
p 'class_instance_var_1=' + @class_instance_var_1.to_s
p 'class_instance_var_2=' + @class_instance_var_2.to_s
p 'class_var=' + @@class_var.to_s
end
end
puts '--- initial status of Foo'
Foo.echo_var
puts '--- initialized Foo'
Foo.new
Foo.echo_var
puts '--- changed Foo'
Foo.change
Foo.echo_var
class Foo2 < Foo
@class_instance_var_2 = 22 # can set here only but not in Foo
@@class_var = 20 # can change here and everywhere
end
puts '--- after Foo2 implementation'
puts '--- Foo'
Foo.echo_var
puts '--- Foo2'
Foo2.echo_var
class Foo3 < Foo2
@class_instance_var_2 = 33 # can set here only but not in Foo
@@class_var = 30 # can change here and everywhere
end
puts '--- after Foo3 implementation'
puts '--- Foo'
Foo.echo_var
puts '--- Foo2'
Foo2.echo_var
puts '--- Foo3'
Foo3.echo_var
输出此
--- initial status of Foo
"class_instance_var_1=0"
"class_instance_var_2=0"
"class_var=10"
--- initialized Foo
"class_instance_var_1=0"
"class_instance_var_2=0"
"class_var=100"
--- changed Foo
"class_instance_var_1=0"
"class_instance_var_2=2"
"class_var=200"
--- after Foo2 implementation
--- Foo
"class_instance_var_1=0"
"class_instance_var_2=2"
"class_var=20"
--- Foo2
"class_instance_var_1="
"class_instance_var_2=22"
"class_var=20"
--- after Foo3 implementation
--- Foo
"class_instance_var_1=0"
"class_instance_var_2=2"
"class_var=30"
--- Foo2
"class_instance_var_1="
"class_instance_var_2=22"
"class_var=30"
--- Foo3
"class_instance_var_1="
"class_instance_var_2=33"
"class_var=30"