” 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 T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
클래스 변수는 모든 “클래스 인스턴스”(예 : 서브 클래스)가 공유하는 반면 클래스 인스턴스 변수는 해당 클래스에만 적용됩니다. 그러나 수업을 연장하지 않으려는 경우 그 차이는 순전히 학문입니다.
답변
인스턴스 메소드에 대한 가용성
- 클래스 인스턴스 변수는 클래스 메서드에만 사용할 수 있으며 인스턴스 메서드에는 사용할 수 없습니다.
- 클래스 변수는 인스턴스 메소드와 클래스 메소드 모두에 사용 가능합니다.
상속
- 상속 체인에서 클래스 인스턴스 변수가 손실됩니다.
- 클래스 변수는 없습니다.
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
(또는 하위 클래스 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" (!)
따라서 수행중인 작업을 정확히 알지 못하고 명시 적으로 이러한 종류의 동작이 필요한 경우가 아니라면 클래스 인스턴스 변수를 사용하는 것이 좋습니다.
답변
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
). 따라서 하나를 수정해도 다른 값은 변경되지 않습니다.
답변
클래스 인스턴스 변수를 활용하는 것이 즉시 유용하게 보일 수 있지만, 클래스 인스턴스 변수는 서브 클래스간에 공유되며 단일 및 인스턴스 메소드 내에서 참조 될 수 있기 때문에 독특한 단점이 있습니다. 그것들은 공유되므로 서브 클래스는 클래스 인스턴스 변수의 값을 변경할 수 있으며 기본 클래스도 변경의 영향을 받아 일반적으로 바람직하지 않은 동작입니다.
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"
Rails는 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"