문제

class Hello
@hello = "hello"
    def display
        puts @hello
    end
end

h = Hello.new
h.display

위의 클래스를 만들었습니다.아무 것도 인쇄하지 않습니다.클래스 선언 중에 인스턴스 변수 @hello가 설정된 줄 알았습니다.하지만 표시 방법을 호출하면 출력은 'nil'입니다.이를 수행하는 올바른 방법은 무엇입니까?

도움이 되었습니까?

해결책

루비의 인스턴스 변수는 루비를 처음 학습 할 때, 특히 Java와 같은 다른 OO 언어에 익숙한 경우 약간 혼란 스러울 수 있습니다.

인스턴스 변수를 간단히 선언 할 수는 없습니다.

Ruby의 인스턴스 변수에 대해 알아야 할 가장 중요한 것 중 하나는 @ Sign Prefix가있는 표기법을 제외하고는 다음과 같습니다. 그들은 처음으로 할당 될 때 생명에 빠졌습니다..

class Hello
  def create_some_state
    @hello = "hello"
  end
end

h = Hello.new
p h.instance_variables 

h.create_some_state
p h.instance_variables

# Output
[]
["@hello"]

메소드를 사용할 수 있습니다 Object#instance_variables 객체의 모든 인스턴스 변수를 나열합니다.

일반적으로 초기화 메소드에서 모든 인스턴스 변수를 "선언"하고 초기화합니다. 공개적으로 사용할 수있는 인스턴스 변수를 명확하게 문서화하는 또 다른 방법은 모듈 방법을 사용하는 것입니다. attr_accessor (읽기/쓰기), attr_writer (쓰기) 및 attr_reader (읽다). 이 방법은 나열된 인스턴스 변수에 대한 다른 액세서 방법을 종합합니다.

class Hello
  attr_accessor :hello
end

h = Hello.new
p h.instance_variables 

h.hello = "hello"
p h.instance_variables

# Output
[]
["@hello"]

인스턴스 변수는 합성을 사용하도록 할당 될 때까지 여전히 생성되지 않습니다. Hello#hello= 방법.

KCH가 설명한 것처럼 또 다른 중요한 문제는 수업을 선언 할 때 활성화 된 다양한 상황을 알고 있어야한다는 것입니다. 수업을 선언 할 때 기본 수신기 (자체) 가장 바깥 범위에는 클래스 자체를 나타내는 객체가됩니다. 따라서 코드는 먼저 할당 할 때 클래스 인스턴스 변수를 만듭니다. @hello 수업 수준에서.

내부 방법 본인 메소드가 호출되는 객체이므로 이름으로 인스턴스 변수의 값을 인쇄하려고합니다. @hello 객체에서 존재하지 않는 객체에서 (기존 인스턴스 변수를 읽는 것이 완벽하게 합법적 임).

다른 팁

추가해야합니다 initialize 방법:

class Hello
    def initialize
        @hello = "hello"
    end
    def display
        puts @hello
    end
end

h = Hello.new
h.display

첫번째 @hello 코드에서는 클래스 인스턴스 변수라고 합니다.

상수가 있는 클래스 객체의 인스턴스 변수입니다. Hello 를 가리키다.(그리고 이는 클래스의 인스턴스입니다. Class.)

기술적으로는 class 범위, 당신의 self 현재 클래스의 객체로 설정되어 있으며 @variables 당신의 현재와 관련된 self.얘야 난 이런 것들을 설명하는 게 짜증나.

다음을 시청하면 이 모든 것을 얻을 수 있고 훨씬 더 명확해질 수 있습니다. The Pragmatic Programmers의 각 5달러짜리 스크린캐스트 모음.

(또는 여기에서 설명을 요청하시면 업데이트하도록 노력하겠습니다.)

"The Ruby Programming Language"라는 책에는 명확한 설명이 있습니다. 읽는 것은 매우 도움이 될 것입니다. 여기에 붙여 넣습니다 (7.1.16 장) :

클래스 정의 내부에서 사용되는 인스턴스 변수이지만 인스턴스 메소드 정의 외부는 클래스 인스턴스 변수.

class Point
    # Initialize our class instance variables in the class definition itself
    @n = 0              # How many points have been created
    @totalX = 0         # The sum of all X coordinates
    @totalY = 0         # The sum of all Y coordinates

    def initialize(x,y) # Initialize method 
      @x,@y = x, y      # Sets initial values for instance variables
    end

    def self.new(x,y)   # Class method to create new Point objects
      # Use the class instance variables in this class method to collect data
      @n += 1           # Keep track of how many Points have been created
      @totalX += x      # Add these coordinates to the totals
      @totalY += y

      super             # Invoke the real definition of new to create a Point
                    # More about super later in the chapter
    end

    # A class method to report the data we collected
    def self.report
        # Here we use the class instance variables in a class method
        puts "Number of points created: #@n"
        puts "Average X coordinate: #{@totalX.to_f/@n}"
        puts "Average Y coordinate: #{@totalY.to_f/@n}"
    end
end

......

클래스 인스턴스 변수는 클래스 객체의 인스턴스 변수 일 뿐이므로 attr, attr_reader 및 attr_accessor를 사용하여 액세서 메소드를 만들 수 있습니다.

class << self
  attr_accessor :n, :totalX, :totalY
end

이러한 액세서가 정의 된 경우 원시 데이터를 Point.n, Point.totalx 및 Point.totaly라고 할 수 있습니다.

루비에는 "클래스 인스턴스 변수"개념이 있다는 것을 잊었습니다. 어쨌든, OP의 문제는 수수께끼처럼 보였고, KCH의 답변에 대한 힌트를 제외하고는 지금까지 어떤 답변에서도 해결되지 않았다. 그것은 범위의 문제이다. (편집에 추가 : 실제로 SRIS의 답변 하다 이 시점을 끝까지 해결하지만, 예제 코드가 문제를 이해하는 데 유용 할 수 있다고 생각하기 때문에 어쨌든이 답변을 견뎌 낼 것입니다.)

루비 클래스에서는 변수 이름이 @ 하나를 참조 할 수 있습니다 변수 : 인스턴스 변수 또는 a 클래스 인스턴스 변수, 수업 시간에 따라 언급 된 위치에 따라. 이것은 상당히 미묘한 Gotcha입니다.

예제는 요점을 명확히 할 것입니다. 다음은 작은 루비 테스트 클래스 (IRB에서 테스트 된 모든 코드)입니다.

class T

  @@class_variable = "BBQ"
  @class_instance_variable_1 = "WTF"
  @class_instance_variable_2 = "LOL"

  def self.class_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def initialize
    @instance_variable = "omg"
    # The following line does not assign a value to the class instance variable,
    # but actually declares an instance variable withthe same name!
    @class_instance_variable_1 = "wtf"
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def instance_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

end

나는 그들이 생각했던 것에 따라 변수를 명명했지만, 항상 그렇지는 않지만 :

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

irb> t = T.new
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf">

irb> t.instance_method
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> nil

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

그만큼 @@class_variable 그리고 @instance_variable 전자는 클래스 수준에서 정의되며 클래스 방법이나 인스턴스 방법에 언급 되든 상단에 할당 된 값을 보유합니다. 후자는 클래스 대상에서만 값을 얻습니다. T, 클래스 메소드에서는 값이있는 알 수없는 변수를 나타냅니다. nil.

클래스 방법은 상상력으로 명명되었습니다 class_method 값을 출력합니다 @@class_variable 그리고 둘 @class_instance_variable예상대로, 즉 클래스의 맨 위에 초기화 된대로. 그러나 인스턴스 방법에서 initialize 그리고 instance_method, 다른 변수 같은 이름의 액세스, 즉 클래스 인스턴스 변수가 아닌 인스턴스 변수.

당신은 그 과제를 볼 수 있습니다 initialize 메소드는 클래스 인스턴스 변수에 영향을 미치지 않았습니다 @class_instance_variable_1, 나중에 전화하기 때문에 class_method 이전 가치를 출력하고 "WTF". 대신, 방법 initialize 새 인스턴스 변수를 선언했습니다. 하나입니다 또한 지명 (오해의 소지가) @class_instance_variable_1. 할당 된 값, "wtf", 방법별로 출력됩니다 initialize 그리고 instance_method.

변수 @class_instance_variable_2 예제에서 코드는 변수와 같습니다 @hello 원래 문제에서 : 클래스 인스턴스 변수로 선언되고 초기화되지만 인스턴스 메소드가 해당 이름의 변수를 지칭하면 실제로 나타납니다. 이름이 같은 인스턴스 변수입니다 - 결코 선언되지 않은 것이 있으므로 그 가치는 nil입니다.

또한 "@@"로 접두사가있는 클래스 변수를 살펴 보는 것이 좋습니다. 다음은 클래스 및 인스턴스 Vars가 어떻게 다른지 보여주는 샘플 코드입니다.

class Vars
  @@classvar="foo"
  def test
    @instancevar="bar"
  end
  def Vars.show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"
  end
  def instance_show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"

  end
end

# only shows classvar since we don't have an instance created
Vars::show
# create a class instance
vars = Vars.new
# instancevar still doesn't show b/c it hasn't been initialized
vars.instance_show
# initialize instancevar
vars.test
# now instancevar shows up as we expect
vars.instance_show
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top