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


517

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

attr_accessor :var
attr_reader :var
attr_writer :var

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


답변:


746

다른 접근자를 사용하여 코드를 읽는 사람에게 의도를 알리고 공용 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 _... 도우미가없고 접근자를 직접 작성해야한다면 클래스에 필요한 것보다 더 많은 접근자를 작성 하시겠습니까? 예를 들어, 나이 만 읽을 필요가 있다면, 그것을 쓸 수있는 방법을 쓰시겠습니까?


53
도 있습니다 상당한 성능 이점은 쓰기에 attr_reader :adef a; return a; end confreaks.net/videos/...
Nitrodist

83
@Nitrodist, 재미있는. Ruby 1.8.7의 경우 attr_reader정의 된 accesor는 수동으로 정의 된 접근자가 수행하는 시간의 86 %가 걸립니다. Ruby 1.9.0의 경우, attr_reader정의 된 접근자는 수동으로 정의 된 접근자가 수행하는 시간의 94 %를 걸립니다. 그러나 모든 테스트에서 접근자는 빠릅니다. 접근자는 약 820 나노초 (Ruby 1.8.7) 또는 440 나노초 (Ruby 1.9)가 걸립니다. 이러한 속도에서 attr_accessor전체 런타임을 1 초까지 향상시킬 수있는 성능 이점을 얻으려면 접근자를 수억 번 호출해야합니다 .
Wayne Conrad

22
"아마도이 클래스의 생성자에 의해 설정되며 일정하게 유지됩니다." 정확하지 않습니다. 독자가있는 인스턴스 변수는 자주 변경 될 수 있습니다. 그러나 해당 값은 클래스에 의해서만 변경 될 수 있습니다.
mlibby

11
","를 사용하여 다음과 같은 두 가지 이상의 속성을 추가 할 수 있습니다.attr_accessor :a, :b
Andrew_1510

2
가치가이 모든 년 후 무엇을 위해 : github.com/JuanitoFatas/... 2.2.0 attr_ * 빠르게 getter 및 setter보다 루비에 대한 최신 벤치 마크에 따라.
molli

25

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


16

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

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


16

접근자는 변수가 아닌 컨텐츠에 대한 액세스를 제한한다는 것을 이해하는 것이 중요합니다. 루비에서 다른 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에서 키 / 값 쌍을 삭제하고 새 키를 추가하고 값을 변경하십시오. 그러나 읽기 전용 인스턴스 변수이므로 새 객체를 가리킬 수 없습니다.


13

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

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