回答:
さまざまなアクセサーを使用して、コードを読んでいる誰かに意図を伝え、パブリックAPIがどのように呼び出されても正しく機能するクラスを簡単に記述できます。
class Person
attr_accessor :age
...
end
ここでは、年齢の読み取りと書き込みの両方ができることがわかります。
class Person
attr_reader :age
...
end
ここでは、年齢のみを読み取ることができることがわかります。このクラスのコンストラクターによって設定され、その後は一定のままであると想像してください。ageにミューテーター(ライター)が存在し、一度設定されたageが変更されないと仮定してクラスが作成された場合、そのミューテーターを呼び出すコードからバグが発生する可能性があります。
しかし、舞台裏で何が起こっているのでしょうか?
あなたが書く場合:
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
定義されたアクセサは、手動で定義されたアクセサが実行する時間の86%かかります。Ruby 1.9.0の場合、attr_reader
定義されたアクセサーは、手動で定義されたアクセサーに比べて94%の時間がかかります。ただし、私のすべてのテストでは、アクセサーは高速です。アクセサーは約820ナノ秒(Ruby 1.8.7)または440ナノ秒(Ruby 1.9)かかります。これらの速度では、attr_accessor
全体的なランタイムを1秒でも改善するというパフォーマンス上の利点を得るために、何億回もアクセサを呼び出す必要があります。
attr_accessor :a, :b
アクセサーは変数へのアクセスを制限しますが、その内容は制限しないことを理解することが重要です。Rubyでは、他のオブジェクト指向言語と同様に、すべての変数がインスタンスへのポインターです。したがって、たとえばハッシュの属性があり、それを「読み取り専用」に設定した場合は、常にその内容を変更できますが、ポインターの内容は変更できません。これを見てください:
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>'
ご覧のとおり、ハッシュ@aからキーと値のペアを削除したり、新しいキーを追加したり、値を変更したりすることができます。ただし、は読み取り専用のインスタンス変数であるため、新しいオブジェクトを指すことはできません。