@@ variable은 Ruby에서 무엇을 의미합니까?


162

이중 변수 ( @@) 앞에 Ruby 변수가 무엇입니까 ? at 기호가 앞에 오는 변수에 대한 이해는 PHP에서 다음과 같은 인스턴스 변수라는 것입니다.

PHP 버전

class Person {

    public $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

루비 동등

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

이중 부호는 무엇을 @@의미하며 단일 부호와 어떻게 다른가요?


103
나도 몰라, 그러나 나는 그것이 나를 쳐다보고 있다는 느낌을 얻는다. 나는 이제 루비로 코드를 작성하는 것이 조금
무섭다

2
TL; 대중을위한 DR : 100 중 99 번, 클래스 변수 ( )가 아닌 "클래스 인스턴스"변수 ( 메서드 @내부 )를 사용합니다. 아래 답변에서 왜 그런지 이유를 참조하십시오. self@@
WattsInABox

답변:


240

접두사가 붙은 변수 @인스턴스 변수 이고 접두사가 붙은 변수@@클래스 변수 입니다. 다음 예를 확인하십시오. 출력은 puts행 끝에 주석에 있습니다.

class Test
  @@shared = 1

  def value
    @@shared
  end

  def value=(value)
    @@shared = value
  end
end

class AnotherTest < Test; end

t = Test.new
puts "t.value is #{t.value}" # 1
t.value = 2
puts "t.value is #{t.value}" # 2

x = Test.new
puts "x.value is #{x.value}" # 2

a = AnotherTest.new
puts "a.value is #{a.value}" # 2
a.value = 3
puts "a.value is #{a.value}" # 3
puts "t.value is #{t.value}" # 3
puts "x.value is #{x.value}" # 3

@@shared클래스간에 공유되는 것을 볼 수 있습니다 . 하나의 인스턴스의 값을 설정하는 변수라는 이름의 클래스, 심지어 아이 클래스의 다른 모든 인스턴스에 대한 값 변경 @shared하나, @하지 않을 것을.

[최신 정보]

Phrogz가 주석에서 언급했듯이 Ruby 자체는 클래스 자체 의 인스턴스 변수로 클래스 레벨 데이터를 추적하는 일반적인 관용구입니다 . 이것은 당신의 마음을 감싸기가 까다로운 주제 일 수 있으며, 주제 에 대한 추가 자료 가 많이 있지만 Class클래스 를 수정하는 것으로 생각 하지만 작업중 인 클래스 의 인스턴스 만 생각 하십시오 Class. 예를 들면 :

class Polygon
  class << self
    attr_accessor :sides
  end
end

class Triangle < Polygon
  @sides = 3
end

class Rectangle < Polygon
  @sides = 4
end

class Square < Rectangle
end

class Hexagon < Polygon
  @sides = 6
end

puts "Triangle.sides:  #{Triangle.sides.inspect}"  # 3
puts "Rectangle.sides: #{Rectangle.sides.inspect}" # 4
puts "Square.sides:    #{Square.sides.inspect}"    # nil
puts "Hexagon.sides:   #{Hexagon.sides.inspect}"   # 6

예상대로 100 % 동작하지 않을 수 있음을 보여주는 Square예제 (출력 nil)를 포함 시켰습니다 . 제가 위에 링크 된 문서 주제에 대한 추가 정보를 많이 가지고있다.

또한 대부분의 데이터와 마찬가지로 dmarkow의 의견 에 따라 다중 스레드 환경 에서 클래스 변수에 매우주의해야합니다 .


1
이 답변은 클래스 수준에서 인스턴스 변수를 사용하여 하위 클래스간에 데이터를 공유하는 '이상한'동작없이 클래스 수준 데이터를 추적하는 방법을 보여주는 코드를 포함하면 완벽한 IMHO가됩니다.
Phrogz

3
또한 다중 스레드 환경 (예 : Rails)에서 클래스 변수가 위험하거나 신뢰할 수 없음을 지적했습니다.
Dylan Markow

흠 ... PHP에서 정적 변수처럼 들리지만 상속 부분이 다릅니다. PHP에는 이와 같은 것이 없다고 생각합니다.
Andrew

5
ruby class << self end블록의 기능, 특히 << 연산자를 이해하지 못합니다 .
davidtingsu 2016 년

1
혼란스러운 다른 사람들을 위해 이것을class << self 참조 하십시오
kapad

37

@-클래스의 인스턴스 변수
@@-클래스 변수, 경우에 따라 정적 변수라고도 함

클래스 변수는 클래스의 모든 인스턴스간에 공유되는 변수입니다. 이는이 클래스에서 인스턴스화 된 모든 객체에 대해 하나의 변수 값만 존재 함을 의미합니다. 하나의 객체 인스턴스가 변수의 값을 변경하면 해당 값은 다른 모든 객체 인스턴스에 대해 본질적으로 변경됩니다.

클래스 변수를 생각하는 또 다른 방법은 단일 클래스의 맥락에서 전역 변수입니다. 클래스 변수는 변수 이름 앞에 두 @문자 ( @@)를 붙여 선언합니다 . 생성시 클래스 변수를 초기화해야합니다


10

@@ 클래스 변수를 나타냅니다. 즉, 상속 될 수 있습니다.

즉, 해당 클래스의 하위 클래스를 만들면 변수가 상속됩니다. 따라서 Vehicle클래스 변수 가있는 클래스 가 @@number_of_wheels있다면 클래스 변수 를 생성 class Car < Vehicle하면 클래스 변수도 갖게됩니다@@number_of_wheels


즉, 해당 클래스의 하위 클래스를 만들면 변수가 상속됩니다. 따라서 Vehicle클래스 변수 @@number_of_wheels를 가진 클래스 가 있다면 클래스 변수 를 만들면 class Car < Vehicle클래스 변수도 갖게됩니다.@@number_of_wheels
Fareesh Vijayarangam

12
나는이있는 경우 class Vehicle@number_of_wheels, 다음 class Car < Vehicle도라는 인스턴스 변수를해야합니다 @number_of_wheels. 클래스 변수와의 주요 차이점은 클래스 에 동일한 변수 가 있다는 것입니다. 예를 들어 한 변수를 변경하면 다른 변수가 변경됩니다.
Michelle Tilley

1

클래스의 @ 및 @@는 클래스가 해당 모듈을 확장하거나 포함 할 때 다르게 작동합니다.

그래서 주어진

module A
    @a = 'module'
    @@a = 'module'

    def get1
        @a          
    end     

    def get2
        @@a         
    end     

    def set1(a) 
        @a = a      
    end     

    def set2(a) 
        @@a = a     
    end     

    def self.set1(a)
        @a = a      
    end     

    def self.set2(a)
        @@a = a     
    end     
end 

그런 다음 아래 출력을 주석으로 표시합니다.

class X
    extend A

    puts get1.inspect # nil
    puts get2.inspect # "module"

    @a = 'class' 
    @@a = 'class' 

    puts get1.inspect # "class"
    puts get2.inspect # "module"

    set1('set')
    set2('set')

    puts get1.inspect # "set" 
    puts get2.inspect # "set" 

    A.set1('sset')
    A.set2('sset')

    puts get1.inspect # "set" 
    puts get2.inspect # "sset"
end 

class Y
    include A

    def doit
        puts get1.inspect # nil
        puts get2.inspect # "module"

        @a = 'class'
        @@a = 'class'

        puts get1.inspect # "class"
        puts get2.inspect # "class"

        set1('set')
        set2('set')

        puts get1.inspect # "set"
        puts get2.inspect # "set"

        A.set1('sset')
        A.set2('sset')

        puts get1.inspect # "set"
        puts get2.inspect # "sset"
    end
end

Y.new.doit

따라서 모든 용도에 공통적으로 사용되는 변수에 대해 모듈에서 @@을 사용하고 모든 사용 컨텍스트에 대해 별도의 변수에 대해 모듈에서 @@를 사용하십시오.


1

@@는 실제로 클래스 계층 당 클래스 변수이므로 클래스, 해당 인스턴스 및 해당 하위 클래스 및 해당 인스턴스가 공유한다는 의미이므로 부분적으로 정확합니다.

class Person
  @@people = []

  def initialize
    @@people << self
  end

  def self.people
    @@people
  end
end

class Student < Person
end

class Graduate < Student
end

Person.new
Student.new

puts Graduate.people

출력됩니다

#<Person:0x007fa70fa24870>
#<Student:0x007fa70fa24848>

따라서 Person, Student 및 Graduate 클래스에 대해 동일한 @@ variable이 하나만 있으며 이러한 클래스의 모든 클래스 및 인스턴스 메소드는 동일한 변수를 참조합니다.

클래스 객체에 정의 된 클래스 변수를 정의하는 또 다른 방법이 있습니다 (각 클래스는 실제로는 실제로 클래스 클래스이지만 다른 이야기 임). @@ 대신 @ 표기법을 사용하지만 인스턴스 메소드에서 이러한 변수에 액세스 할 수 없습니다. 클래스 메소드 랩퍼가 있어야합니다.

class Person

  def initialize
    self.class.add_person self
  end

  def self.people
    @people
  end

  def self.add_person instance
    @people ||= []
    @people << instance
  end
end

class Student < Person
end

class Graduate < Student
end

Person.new
Person.new
Student.new
Student.new
Graduate.new
Graduate.new

puts Student.people.join(",")
puts Person.people.join(",")
puts Graduate.people.join(",")

여기서 @people은 실제로 각 클래스 인스턴스에 저장된 변수이기 때문에 클래스 계층 구조 대신 클래스 당 단일입니다. 이것은 출력입니다.

#<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38>
#<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608>
#<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8> 

한 가지 중요한 차이점은 인스턴스 메소드의 @people가 Person 또는 Student 또는 Graduate 클래스의 특정 인스턴스의 인스턴스 변수를 참조하기 때문에 인스턴스 메소드에서 직접 이러한 클래스 변수 (또는 말할 수있는 클래스 인스턴스 변수)에 액세스 할 수 없다는 것입니다 .

따라서 다른 답변에 @myvariable (단일 @ 표기법 사용)이 항상 인스턴스 변수라고 명시되어 있지만 반드시 해당 클래스의 모든 인스턴스에 대해 단일 공유 변수가 아님을 의미하지는 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.