루비 클래스 인스턴스 변수 대 클래스 변수
"Ruby 인스턴스 변수는 언제 설정됩니까?"를 읽지만 클래스 인스턴스 변수를 사용할 때는 두 가지 생각이 있습니다.
클래스 변수는 클래스의 모든 개체에서 공유되며 인스턴스 변수는 하나의 개체에 속합니다.클래스 변수가 있으면 클래스 인스턴스 변수를 사용할 수 있는 공간이 얼마 남지 않습니다.
누가 이 둘의 차이점과 언제 사용해야 하는지 설명해 주시겠습니까?
다음은 코드 예제입니다.
class S
@@k = 23
@s = 15
def self.s
@s
end
def self.k
@@k
end
end
p S.s #15
p S.k #23
업데이트: 이제 이해했습니다!클래스 인스턴스 변수는 상속 체인을 따라 전달되지 않습니다.
클래스의 인스턴스 변수:
class Parent
@things = []
def self.things
@things
end
def things
self.class.things
end
end
class Child < Parent
@things = []
end
Parent.things << :car
Child.things << :doll
mom = Parent.new
dad = Parent.new
p Parent.things #=> [:car]
p Child.things #=> [:doll]
p mom.things #=> [:car]
p dad.things #=> [:car]
클래스 변수:
class Parent
@@things = []
def self.things
@@things
end
def things
@@things
end
end
class Child < Parent
end
Parent.things << :car
Child.things << :doll
p Parent.things #=> [:car,:doll]
p Child.things #=> [:car,:doll]
mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new
[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
클래스의 인스턴스 변수(해당 클래스의 인스턴스가 아님)를 사용하면 하위 클래스가 자동으로 가져올 필요 없이 해당 클래스에 공통적인 것을 저장할 수 있습니다(그 반대의 경우도 마찬가지입니다.클래스 변수를 사용하면, 당신은 쓸 필요가 없는 편리함을 가지고 있습니다.self.class인스턴스 개체에서 클래스 계층 전체에 걸쳐 자동 공유도 얻을 수 있습니다.
인스턴스의 인스턴스 변수도 다루는 단일 예제로 병합:
class Parent
@@family_things = [] # Shared between class and subclasses
@shared_things = [] # Specific to this class
def self.family_things
@@family_things
end
def self.shared_things
@shared_things
end
attr_accessor :my_things
def initialize
@my_things = [] # Just for me
end
def family_things
self.class.family_things
end
def shared_things
self.class.shared_things
end
end
class Child < Parent
@shared_things = []
end
그리고 나서 행동합니다.
mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new
Parent.family_things << :house
papa.family_things << :vacuum
mama.shared_things << :car
papa.shared_things << :blender
papa.my_things << :quadcopter
joey.my_things << :bike
suzy.my_things << :doll
joey.shared_things << :puzzle
suzy.shared_things << :blocks
p Parent.family_things #=> [:house, :vacuum]
p Child.family_things #=> [:house, :vacuum]
p papa.family_things #=> [:house, :vacuum]
p mama.family_things #=> [:house, :vacuum]
p joey.family_things #=> [:house, :vacuum]
p suzy.family_things #=> [:house, :vacuum]
p Parent.shared_things #=> [:car, :blender]
p papa.shared_things #=> [:car, :blender]
p mama.shared_things #=> [:car, :blender]
p Child.shared_things #=> [:puzzle, :blocks]
p joey.shared_things #=> [:puzzle, :blocks]
p suzy.shared_things #=> [:puzzle, :blocks]
p papa.my_things #=> [:quadcopter]
p mama.my_things #=> []
p joey.my_things #=> [:bike]
p suzy.my_things #=> [:doll]
인스턴스 메소드에 대한 가용성
- 클래스 인스턴스 변수는 클래스 메서드에만 사용할 수 있고 인스턴스 메서드에는 사용할 수 없습니다.
- 클래스 변수는 인스턴스 메서드와 클래스 메서드 모두에서 사용할 수 있습니다.
상속 가능성
- 클래스 인스턴스 변수가 상속 체인에서 손실됩니다.
- 클래스 변수는 그렇지 않습니다.
class Vars
@class_ins_var = "class instance variable value" #class instance variable
@@class_var = "class variable value" #class variable
def self.class_method
puts @class_ins_var
puts @@class_var
end
def instance_method
puts @class_ins_var
puts @@class_var
end
end
Vars.class_method
puts "see the difference"
obj = Vars.new
obj.instance_method
class VarsChild < Vars
end
VarsChild.class_method
주요 차이점은 상속이라고 생각합니다.
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
클래스 변수는 모든 "클래스 인스턴스"(즉, 하위 클래스)에서 공유되지만 클래스 인스턴스 변수는 해당 클래스에만 한정됩니다.하지만 수업을 연장할 생각이 전혀 없다면, 그 차이는 순전히 학문적인 것입니다.
다른 사람들이 말했듯이, 클래스 변수는 주어진 클래스와 해당 하위 클래스 간에 공유됩니다.클래스 인스턴스 변수는 정확히 하나의 클래스에 속하며, 해당 하위 클래스는 별도입니다.
왜 이런 행동이 존재합니까?루비의 모든 것은 객체입니다. 심지어 클래스도 마찬가지입니다.즉, 각 클래스에는 클래스의 개체가 있습니다.Class( 오히려 , 하위래스의는▁of)의 Class에 해당합니다. ( )라고 때는. ( )라고 합니다.class Foo당신은 정말로 상수를 선언하고 있습니다.Foo클래스 개체를 할당합니다.)그리고 모든 Ruby 객체는 인스턴스 변수를 가질 수 있으므로 클래스 객체도 인스턴스 변수를 가질 수 있습니다.
문제는 클래스 개체의 인스턴스 변수가 실제로 클래스 변수가 일반적으로 원하는 방식으로 동작하지 않는다는 것입니다.일반적으로 수퍼 클래스에 정의된 클래스 변수를 하위 클래스와 공유하려고 하지만 인스턴스 변수의 작동 방식은 다릅니다. 하위 클래스에는 고유한 클래스 개체가 있고 해당 클래스 개체에는 고유한 인스턴스 변수가 있습니다.그래서 그들은 여러분이 더 원하는 행동을 가진 별도의 클래스 변수를 도입했습니다.
즉, 클래스 인스턴스 변수는 Ruby 설계의 사고입니다.당신이 찾고 있는 것이 그것들이라는 것을 구체적으로 알지 못하는 한, 당신은 아마도 그것들을 사용하지 말아야 할 것입니다.
공식 루비 FAQ: 클래스 변수와 클래스 인스턴스 변수의 차이점은 무엇입니까?
주요 차이점은 상속과 관련된 동작입니다. 클래스 변수는 클래스와 모든 하위 클래스 간에 공유되지만 클래스 인스턴스 변수는 특정 클래스 하나에만 속합니다.
클래스 변수는 글로벌 변수와 함께 발생하는 모든 문제와 함께 상속 계층의 컨텍스트 내에서 글로벌 변수로 볼 수 있습니다.예를 들어, 클래스 변수는 해당 하위 클래스에 의해 (우연히) 재할당되어 다른 모든 클래스에 영향을 줄 수 있습니다.
class Woof
@@sound = "woof"
def self.sound
@@sound
end
end
Woof.sound # => "woof"
class LoudWoof < Woof
@@sound = "WOOF"
end
LoudWoof.sound # => "WOOF"
Woof.sound # => "WOOF" (!)
또는 다음과 같은 놀라운 효과로 인해 나중에 조상 클래스가 다시 열리고 변경될 수 있습니다.
class Foo
@@var = "foo"
def self.var
@@var
end
end
Foo.var # => "foo" (as expected)
class Object
@@var = "object"
end
Foo.var # => "object" (!)
따라서 사용자가 수행 중인 작업을 정확히 알고 있고 이러한 종류의 동작이 명시적으로 필요하지 않은 경우 클래스 인스턴스 변수를 사용하는 것이 좋습니다.
클래스 변수를 활용하는 것이 즉시 유용해 보일 수 있지만, 클래스 변수는 하위 클래스 간에 공유되고 싱글톤 및 인스턴스 방법 내에서 모두 참조될 수 있기 때문에 상당한 단점이 있습니다.이들은 공유되므로 하위 클래스가 클래스 변수의 값을 변경할 수 있으며 기본 클래스도 변경의 영향을 받습니다. 이는 일반적으로 바람직하지 않은 동작입니다.
class C
@@c = 'c'
def self.c_val
@@c
end
end
C.c_val
=> "c"
class D < C
end
D.instance_eval do
def change_c_val
@@c = 'd'
end
end
=> :change_c_val
D.change_c_val
(irb):12: warning: class variable access from toplevel
=> "d"
C.c_val
=> "d"
레일즈는 class_attribute라고 하는 편리한 방법을 소개합니다.이름에서 알 수 있듯이 하위 클래스에서 값을 상속할 수 있는 클래스 수준 특성을 선언합니다.class_attribute 값은 클래스 변수의 경우와 마찬가지로 싱글턴 메서드와 인스턴스 메서드 모두에서 액세스할 수 있습니다.그러나 Rails에서 class_attribute의 큰 이점은 하위 클래스가 자체 값을 변경할 수 있으며 상위 클래스에 영향을 미치지 않는다는 것입니다.
class C
class_attribute :c
self.c = 'c'
end
C.c
=> "c"
class D < C
end
D.c = 'd'
=> "d"
C.c
=> "c"
C++ 배경을 가진 사람들의 경우 C++ 동등물과의 비교에 관심이 있을 것입니다.
class S
{
private: // this is not quite true, in Ruby you can still access these
static int k = 23;
int s = 15;
public:
int get_s() { return s; }
static int get_k() { return k; }
};
std::cerr << S::k() << "\n";
S instance;
std::cerr << instance.s() << "\n";
std::cerr << instance.k() << "\n";
보다시피,k이다.static등변량클래스에서 소유한다는 점(정확한 범위)을 제외하고는 전역 변수와 100% 유사합니다.이렇게 하면 유사하게 명명된 변수 간의 충돌을 보다 쉽게 방지할 수 있습니다.다른 글로벌 변수와 마찬가지로 해당 변수의 인스턴스가 하나만 있으며 이를 수정하는 작업은 항상 모든 사용자가 볼 수 있습니다.
반면에,s개체별 값입니다.각 개체에는 고유한 값 인스턴스가 있습니다.C++에서 해당 변수에 액세스하려면 인스턴스를 만들어야 합니다.Ruby에서 클래스 정의 자체는 클래스의 인스턴스입니다(JavaScript에서는 이것을 프로토타입이라고 부릅니다). 따라서 액세스할 수 있습니다.s추가 인스턴스화 없이 클래스에서.클래스 인스턴스는 수정할 수 있지만, 수정할 수 없습니다.s각 인스턴스(유형의 각 개체)에 특정됩니다.S. 따라서 하나를 수정해도 다른 하나의 값은 변경되지 않습니다.
간단한 예를 보여주기
- 클래스 변수의 상속 가능성
- 클래스 인스턴스(instance) 변수의 캡슐화
참고: 의 사용 방법class << self이 블록 내의 모든 메서드를 다음으로 추가하는 대신 편리합니다.self.참고: 더class << self수정합니다.self그래서 그것은 메타 클래스를 가리킵니다.Parent(https://stackoverflow.com/a/38041660/960184) 참조)
예제 코드
class Parent
class << self
attr_reader :class_instance_var
def class_instance_var=(value)
@class_instance_var="set by #{self.name} to #{value}"
end
def class_var
@@class_var
end
def class_var=(value)
@@class_var = "set by #{self.name} to #{value}"
end
end
end
class Child < Parent
end
# use the instance separately in parent and subclass
puts "\n* Exercising class instance variable setters
* Setting Parent and Child class instance variables differently
* Parent.class_instance_var = 1000\n* Child.class_instance_var = 2000\n\n"
Parent.class_instance_var = 1000
Child.class_instance_var = 2000
puts "Parent.class_instance_var=(#{Parent.class_instance_var})"
puts "Child.class_instance_var=(#{Child.class_instance_var})"
# set class variable in via parent (changes both in parent and subclass)
puts "\n* Exercising Parent class variable setter
* Set class variable value to 3000 using parent, it changes in Child also
* Parent.class_var = 3000\n\n"
Parent.class_var = 3000
puts "Parent.class_var=(#{Parent.class_var})"
puts "Child.class_var=(#{Child.class_var})"
# set class variable in via subclass (changes both in parent and subclass)
puts "\n* Exercising Child class variable setter
* Set class variable value to 5000 using child, it changes in Parent also
* Child.class_var = 5000\n\n"
Child.class_var = 5000
puts "Parent.class_var=(#{Parent.class_var})"
puts "Child.class_var=(#{Child.class_var})"
루비 v3.0.2를 사용한 출력
* Exercising class instance variable setters
* Setting Parent and Child class instance variables differently
* Parent.class_instance_var = 1000
* Child.class_instance_var = 2000
Parent.class_instance_var=(set by Parent to 1000)
Child.class_instance_var=(set by Child to 2000)
* Exercising Parent class variable setter
* Set class variable value to 3000 using parent, it changes in Child also
* Parent.class_var = 3000
Parent.class_var=(set by Parent to 3000)
Child.class_var=(set by Parent to 3000)
* Exercising Child class variable setter
* Set class variable value to 5000 using child, it changes in Parent also
* Child.class_var = 5000
Parent.class_var=(set by Child to 5000)
Child.class_var=(set by Child to 5000)
언급URL : https://stackoverflow.com/questions/15773552/ruby-class-instance-variable-vs-class-variable
'programing' 카테고리의 다른 글
| 중첩 배열의 MongoDB 투영 (0) | 2023.06.03 |
|---|---|
| 루비에서 난수를 얻는 방법 (0) | 2023.06.03 |
| UI 레이블 주위에 테두리를 그리는 방법은 무엇입니까? (0) | 2023.06.03 |
| SQL Server Reporting Services(VB)에서 이전 달력 달의 첫째 날과 마지막 날을 찾습니다.네트) (0) | 2023.05.09 |
| git의 "rebase --reserve-merges"가 정확히 무엇을 하는 것입니까 (그리고 그 이유는 무엇입니까?) (0) | 2023.05.09 |