538

Rubyには、次のようなキーを使用してインスタンス変数を共有するための便利で便利な方法があります。

attr_accessor :var
attr_reader :var
attr_writer :var

なぜ私が選ぶのでしょうかattr_reader、それともattr_writer単に使用できるのattr_accessorでしょうか?パフォーマンスのようなものはありますか(私は疑っています)?理由があると思います。そうでなければ、そのようなキーを作成しなかったでしょう。

4

5 に答える 5

767

さまざまなアクセサーを使用して、コードを読んでいる誰かに意図を伝え、パブリック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 _...ヘルパーがなく、アクセサを自分で作成する必要がある場合、クラスに必要な数よりも多くのアクセサを作成しますか?たとえば、年齢を読み取るだけでよい場合、それを書き込むことができるメソッドも記述しますか?

于 2011-02-18T21:43:27.623 に答える
27
于 2011-04-27T15:11:43.047 に答える
17

アクセサは変数へのアクセスを制限しますが、その内容は制限しないことを理解することが重要です。ルビーでは、他のいくつかのオブジェクト指向言語と同様に、すべての変数はインスタンスへのポインターです。したがって、たとえばハッシュの属性があり、それを「読み取り専用」に設定した場合、常にそのコンテンツを変更できますが、ポインタのコンテンツは変更できません。これを見てください:

> class A
>   attr_reader :a
>   def initialize
>     @a = {a:1, b:2}
>   end
> end
=> :initialize
> a = A.new
=> #<A:0x007ffc5a10fe88 @a={:a=>1, :b=>2}>
> a.a
=> {:a=>1, :b=>2}
> a.a.delete(:b)
=> 2
> a.a
=> {:a=>1}
> a.a = {}
NoMethodError: undefined method `a=' for #<A:0x007ffc5a10fe88 @a={:a=>1}>
        from (irb):34
        from /usr/local/bin/irb:11:in `<main>'

ご覧のとおり、ハッシュ@aからキーと値のペアを削除し、新しいキーを追加したり、値を変更したりすることができます。ただし、は読み取り専用のインスタンス変数であるため、新しいオブジェクトを指すことはできません。

于 2015-07-02T16:10:02.777 に答える
16

オブジェクトのすべての属性がクラスの外部から直接設定されることを意図しているわけではありません。すべてのインスタンス変数にライターがあるということは、一般に、カプセル化が弱いことの兆候であり、クラス間に過度の結合を導入していることを警告しています。

実用的な例として:私はあなたがコンテナの中にアイテムを入れるデザインプログラムを書きました。アイテムは持っていましたattr_reader :containerが、ライターを提供することは意味がありませんでした。アイテムのコンテナを変更する必要があるのは、新しいコンテナに配置するときだけであり、これには位置情報も必要です。

于 2011-02-18T22:28:55.493 に答える
13

クラスの外部からインスタンス変数に完全にアクセスできるようにする必要はありません。インスタンス変数への読み取りアクセスを許可することは理にかなっているが、それに書き込むことは理にかなっていない場合がたくさんあります(たとえば、読み取り専用ソースからデータを取得するモデル)。逆の場合もありますが、頭のてっぺんから工夫されていないものは思い浮かびません。

于 2011-02-18T21:42:24.467 に答える