[ruby] 왜 Ruby의 attr_accessor, attr_reader 및 attr_writer를 사용합니까?

Ruby는 다음과 같은 키를 사용하여 인스턴스 변수를 공유하는이 편리하고 편리한 방법을 제공합니다

attr_accessor :var
attr_reader :var
attr_writer :var

내가 왜 선택 attr_reader하거나 attr_writer간단하게 사용할 수 attr_accessor있습니까? 성능과 같은 것이 있습니까? 나는 이유가 있다고 생각합니다. 그렇지 않으면 그들은 그러한 열쇠를 만들지 않았을 것입니다.



답변

다른 접근자를 사용하여 코드를 읽는 사람에게 의도를 알리고 공용 API 호출 방법에 관계없이 올바르게 작동하는 클래스를 더 쉽게 작성할 수 있습니다.

class Person
  attr_accessor :age
  ...
end

여기서 나는 나이를 읽고 쓸 수 있음을 알 수 있습니다.

class Person
  attr_reader :age
  ...
end

여기에서는 나이 만 읽을 수 있음을 알 수 있습니다. 이 클래스의 생성자에 의해 설정되고 그 후에도 일정하다고 가정하십시오. 연령에 대한 뮤 테이터 (작성자)가 있고 해당 나이가 설정된 후에 변경되지 않는다고 가정하여 클래스를 작성한 경우 해당 뮤 테이터를 호출하는 코드에서 버그가 발생할 수 있습니다.

그러나 무대 뒤에서 무슨 일이 일어나고 있습니까?

당신이 쓰는 경우 :

attr_writer :age

그것은 다음과 같이 번역됩니다.

def age=(value)
  @age = value
end

당신이 쓰는 경우 :

attr_reader :age

그것은 다음과 같이 번역됩니다.

def age
  @age
end

당신이 쓰는 경우 :

attr_accessor :age

그것은 다음과 같이 번역됩니다.

def age=(value)
  @age = value
end

def age
  @age
end

그것을 아는 것은 여기에 다른 생각이 있습니다. attr _… 도우미가없고 접근자를 직접 작성해야한다면 클래스에 필요한 것보다 더 많은 접근자를 작성 하시겠습니까? 예를 들어, 나이 만 읽을 필요가 있다면, 그것을 쓸 수있는 방법을 쓰시겠습니까?


답변

위의 모든 답변은 정확합니다. attr_reader그리고 attr_writer수동으로 그들이 shorthands있는 방법을 입력하는 것보다 쓰는 것이 더 편리합니다. 그 외에도 메소드 정의를 직접 작성하는 것보다 훨씬 나은 성능을 제공합니다. 자세한 내용 은 Aaron Patterson 의이 강의 ( PDF ) 슬라이드 152 이상을 참조하십시오 .


답변

객체의 모든 속성이 클래스 외부에서 직접 설정되는 것은 아닙니다. 모든 인스턴스 변수에 대한 작성자를 갖는 것은 일반적으로 캡슐화가 약하다는 표시이며 클래스간에 너무 많은 커플 링을 도입하고 있다는 경고입니다.

실용적인 예로 : 컨테이너 안에 아이템을 넣는 디자인 프로그램을 작성했습니다. attr_reader :container아이템의 컨테이너가 바뀌어야 할 유일한 시간은 위치 정보가 필요하기 때문에 아이템 컨테이너가 바뀌어야하는 유일한 시간이기 때문에 아이템을 가지고 있지만 작가에게 제공하는 것은 의미가 없습니다.


답변

접근자는 변수가 아닌 컨텐츠에 대한 액세스를 제한한다는 것을 이해하는 것이 중요합니다. 루비에서 다른 OO 언어와 마찬가지로 모든 변수는 인스턴스에 대한 포인터입니다. 예를 들어, 해시에 대한 속성이 있고이를 “읽기 전용”으로 설정하면 항상 내용을 변경할 수 있지만 포인터 내용은 변경할 수 없습니다. 이것 좀봐:

irb(main):024:0> class A
irb(main):025:1> attr_reader :a
irb(main):026:1> def initialize
irb(main):027:2> @a = {a:1, b:2}
irb(main):028:2> end
irb(main):029:1> end
=> :initialize
irb(main):030:0> a = A.new
=> #<A:0x007ffc5a10fe88 @a={:a=>1, :b=>2}>
irb(main):031:0> a.a
=> {:a=>1, :b=>2}
irb(main):032:0> a.a.delete(:b)
=> 2
irb(main):033:0> a.a
=> {:a=>1}
irb(main):034:0> a.a = {}
NoMethodError: undefined method `a=' for #<A:0x007ffc5a10fe88 @a={:a=>1}>
        from (irb):34
        from /usr/local/bin/irb:11:in `<main>'

보시다시피 Hash @a에서 키 / 값 쌍을 삭제하고 새 키를 추가하고 값을 변경하십시오. 그러나 읽기 전용 인스턴스 변수이므로 새 객체를 가리킬 수 없습니다.


답변

클래스 외부에서 인스턴스 변수에 항상 액세스 할 수있는 것은 아닙니다. 인스턴스 변수에 대한 읽기 액세스를 허용하는 경우가 많지만 여기에 쓰지 않을 수 있습니다 (예 : 읽기 전용 소스에서 데이터를 검색하는 모델). 당신이 반대를 원하는 경우가 있지만, 나는 내 머리 꼭대기에서 벗어나지 않은 것을 생각할 수 없습니다.


답변