Bất cứ ai có thể cho tôi biết về sự khác biệt giữa các biến lớp và các biến cá thể lớp không?
Câu trả lời:
Một biến lớp ( @@
) được chia sẻ giữa lớp và tất cả các biến lớp con của nó. Một biến cá thể của lớp ( @
) không được chia sẻ bởi con cháu của lớp.
Biến lớp ( @@
)
Hãy có một lớp Foo với một biến lớp @@i
và các trình truy cập để đọc và ghi @@i
:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
Và một lớp dẫn xuất:
class Bar < Foo
end
Chúng tôi thấy rằng Foo và Bar có cùng giá trị đối với @@i
:
p Foo.i # => 1
p Bar.i # => 1
Và thay đổi @@i
trong một thay đổi nó trong cả hai:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Biến cá thể lớp ( @
)
Hãy tạo một lớp đơn giản với biến cá thể của lớp @i
và các trình truy cập để đọc và ghi @i
:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
Và một lớp dẫn xuất:
class Bar < Foo
end
Chúng ta thấy rằng mặc dù Bar kế thừa các trình truy cập cho @i
, nó không kế thừa @i
chính nó:
p Foo.i # => 1
p Bar.i # => nil
Chúng tôi có thể đặt Bar's @i
mà không ảnh hưởng đến Foo's @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
Đầu tiên, bạn phải hiểu rằng các lớp cũng là các cá thể - các cá thể của Class
lớp.
Khi bạn hiểu điều đó, bạn có thể hiểu rằng một lớp có thể có các biến cá thể được liên kết với nó giống như một đối tượng thông thường (read: non-class) có thể.
Hello = Class.new
# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")
# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"
Lưu ý rằng một biến cá thể trên Hello
hoàn toàn không liên quan và khác biệt với một biến cá thể trên một phiên bản củaHello
hello = Hello.new
# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")
# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")
# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"
Mặt khác, một biến lớp là một kiểu kết hợp của hai biến trên, vì nó có thể truy cập được trên Hello
chính nó và các thể hiện của nó, cũng như trên các lớp con Hello
và các thể hiện của chúng:
HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new
Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"
Nhiều người nói hãy tránh class variables
vì hành vi kỳ lạ trên, đồng thời khuyến cáo sử dụng class instance variables
thay thế.
Ngoài ra, tôi muốn nói thêm rằng bạn có thể có quyền truy cập vào biến lớp ( @@
) từ bất kỳ trường hợp nào của lớp
class Foo
def set_name
@@name = 'Nik'
end
def get_name
@@name
end
end
a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik
Nhưng bạn không thể làm như vậy đối với biến cá thể lớp ( @
)
class Foo
def set_name
@name = 'Nik'
end
def get_name
@name
end
end
a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil
Foo.i
, nhưng làm thế nào bạn có thể làm điều tương tự cho mọi trường hợp của lớp này như thế Foo.new.i
nào?
#class
. Cá nhân tôi nghĩ rằng #class
tập quán khi được gọi trên bất cứ thứ gì nhưng chỉ self
là mùi mã. Bạn thậm chí có thể tiến thêm một bước nữa và triển khai các trình truy cập cá thể i
và i=
ủy quyền cho các đối tượng #class
tương đương của chúng , trong trường hợp đó bạn có thể làm được Foo.new.i
. Tôi không khuyên bạn nên làm điều đó vì nó tạo ra một giao diện khó hiểu, cho thấy rằng bạn đang sửa đổi một thành viên đối tượng.