2011-09-26 4 views
3

Ruby 코드에서 사용 된 인스턴스 변수 규칙이 있습니까?인스턴스 변수에는 어떤 규칙을 사용해야합니까?

class BookInStock 
    attr_reader: isbn 
    attr_accessor: price 

    def initialize (isbn, price) 
    @isbn = isbn 
    @price = Float (price) 
    end 

    def price_in_cents 
    Integer (price * 100 + 0.5) 
    end 
end 

을 그리고 예제 코드는이있다 : 즉, 나는 '@'예 섹션에서, 인스턴스 변수는 '@'를 사용하여 초기화 된 후 코드가없는 변수 이름을 사용 나타났습니다 인스턴스 변수는 항상 '@'접두어로 사용됩니다.

class BookStock 

    def set_price (price) 
    @price = price 
    end 

    def get_price 
    @price 
    end 
end 

이 레코드의 차이점은 무엇입니까? 언제 개체의 초기화와 모든 클래스 메서드에서 '@'사용해야합니까?

+0

[루비의 복제본은 내가 스스로 사용해야합니다. 또는 @] (http://stackoverflow.com/questions/5275749/ruby-should-i-use-self-or) –

답변

6

이 변수에 대한 속성 판독기 (attr_reader 또는 attr_accessor)를 정의한 경우에만 @없이 인스턴스 변수 이름을 사용할 수 있습니다. 인스턴스 변수의 값을 반환하는 메서드를 만드는 가벼운 도우미입니다.

의 차이는 클래스의 공용 인터페이스를 사용하거나 개인 데이터에 접근 사이의 문제이다. 예를 들어 서브 클래스 또는 포함 된 모듈에서 공용 인터페이스를 사용하는 것이 좋습니다. 이렇게하면 캡슐화가 보장됩니다. 따라서 하위 클래스 또는 모듈 내에서 인스턴스 변수에 액세스하면 안됩니다.

클래스 자체에서이 질문을 물어보십시오. 속성 구현이 변경되면 내 용도 속성도 변경되어야합니까? 대답이 이면 인스턴스 변수를 직접 사용하십시오. 이 아닌 경우이면 public 특성을 사용하십시오.

예. 사람을 나타내는 그 사람의 이름을 포함해야하는 Person 클래스가 있다고 가정합니다.우리가 blank? 방법에 대한인스턴스 변수를 사용하는 방법

class Person 
    attr_reader :name 

    def initialize(name) 
    @name = name 
    end 

    def blank? 
    [email protected] 
    end 

    def to_s 
    name 
    end 
end 

참고하지만, to_s 방법에 대한 public 특성 : 우선 단지 간단한 name 속성이 버전이있다. 이것은 의도적 인 것입니다!

리팩터링 단계에서 우리는 Person 클래스가 first_namelast_name을 별도로 추적해야한다고 결정했다고 가정 해 보겠습니다.

class Person 
    def initialize(first_name, last_name) 
    @first_name, @last_name = first_name, last_name 
    end 

    def name 
    "#{@first_name} #{@last_name}" 
    end 

    def blank? 
    [email protected]_name and [email protected]_name 
    end 

    def to_s 
    name 
    end 
end 

우리는 지금 사람의 성과 이름에서 이름을 구성하는 일반적인 방법에 name 속성을 변경합니다. 이제 to_s에 대해 동일한 구현을 유지하는 것이 가능하다는 것을 알 수 있습니다. 그러나 기본 데이터에 종속되어 있기 때문에 blank?을 변경해야합니다. 이것이 to_s속성을 사용했지만 blank?이 인 을 사용하는 이유입니다.

당연히 구별이 항상 쉬운 것은 아닙니다. 의심스러운 경우 개인 데이터에 액세스하는 것 이상의 공용 API를 선택하십시오.

6

첫 번째 예에서는 @price이 인스턴스 변수입니다.

price_in_cents에 대한 메서드 정의에서 price은 실제로 price()에 대한 메서드 호출입니다. Ruby의 구문 설탕 때문에 ()은 생략되었습니다. 이 price()에 대한 명시 적 정의 없지만 attr_accessor :priceprice()price=(value) 일명, getter와 setter를 모두 정의처럼

는 것 같습니다. BookInStock의 인스턴스가 price_in_cents 일 때 attr_accessor :price 행을 주석 처리 할 수 ​​있습니다. "정의되지 않은 로컬 변수 또는 메소드"예외가 발생합니다.

인스턴스 변수의 접두어는 항상 @입니다. 접근 자 메서드가 정의되지 않은 경우 @ 접두사없이 해당 이름을 사용할 수 없습니다.

+0

좋은 대답은, 나는 작은 작은 뾰족 함을 가지고있다 :'price =()'는'price = (value)'이고 클래스 정의에 관한 마지막 비트는 약간 분명하지 않다. –

+0

조언에 따라 조금 수정되었습니다. 감사. – venj

+0

문제 없음, 좋은 답변을 계속! –

1

name = value을 사용하면 name이라는 로컬 변수가 만들어지기 때문에 오류입니다. self.name = value을 사용해야합니다.

접근 규칙이 항상 경량 attr_accessors가되도록 보장 할 수있는 경우 규칙대로는 @name을 사용하면됩니다. 그 밖의 경우에는 self.name보다 @name을 사용하면 캡슐화에 위배되며 두통이 발생합니다. 질문에 정확한 이유를 제시했습니다. getter/setter에 여분의 논리가있는 경우 인스턴스 변수에 직접 액세스하면 복제해야합니다.

관련 문제