web-dev-qa-db-ja.com

Rubyのattr_accessorとは何ですか?

私はRubyのattr_accessorを理解するのに苦労しています。誰かが私にこれを説明できますか?

951
dennismonsewicz

Personというクラスがあるとしましょう。

class Person
end

person = Person.new
person.name # => no method error

明らかに、メソッドnameを定義したことは一度もありません。それをしましょう。

class Person
  def name
    @name # simply returning an instance variable @name
  end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

ああ、私たちは名前を読むことができますが、それは私たちが名前を割り当てることができるという意味ではありません。それらは2つの異なる方法です。前者は reader と呼ばれ、後者は writer と呼ばれます。作家はまだ作成していないので、それをしましょう。

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

驚くばかり。これで、リーダーメソッドとライターメソッドを使用してインスタンス変数@nameを読み書きできます。例外として、これは頻繁に行われますが、なぜこれらのメソッドを毎回書くのに無駄な時間がかかるのでしょうか。もっと簡単にできます。

class Person
  attr_reader :name
  attr_writer :name
end

これでも繰り返しになることがあります。読者と作家の両方が欲しいときはただアクセサを使うだけ!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

同じように動作します!そしてどう思いますか:personオブジェクトのインスタンス変数@nameは、手動で行ったときと同じように設定されるので、他のメソッドで使用できます。

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

それでおしまい。 attr_readerattr_writer、およびattr_accessorメソッドが実際にどのようにメソッドを生成するのかを理解するために、他の回答、書籍、Rubyのドキュメントを読んでください。

2198
Max Chernyak

attr_accessor単なるメソッド です。 (リンクはそれがどのように働くかについてのより多くの洞察を提供するべきです - 生成されたメソッドのペアを見てください、そしてチュートリアルはあなたがそれをどのように使うかを示すべきです。)

トリックは、Rubyではclass定義ではない (C++やJavaなどの言語では「単なる定義」である)ですが、 評価される式 です。この評価中に、attr_accessorメソッドが呼び出されて現在のクラスが変更されます。暗黙のレシーバself.attr_accessorを覚えておいてください。ここで、selfは、この時点での "open"クラスオブジェクトです。

attr_accessorと友達の必要性は、そうです:

  1. Smalltalkのように、Rubyはインスタンス変数にメソッド外からアクセスすることを許可していません。1 そのオブジェクトのために。つまり、インスタンス変数はx.y形式でアクセスすることはできません。JavaやPythonでさえも一般的です。 Rubyではyは常に送信するメッセージ(または「呼び出すメソッド」)として扱われます。したがって、attr_*メソッドは、動的に作成されたメソッドを通じてインスタンス@variableアクセスを代行するラッパーを作成します。

  2. ボイラープレートは吸う

これが細部のいくつかを明確にすることを願っています。ハッピーコーディング.


1 これは厳密には真実ではなく、 これに関するいくつかの "テクニック" がありますが、 "public instance variable"アクセスに対する構文サポートはありません。

120
user166390

attr_accessorは(@pstが述べたように)単なるメソッドです。それがすることはあなたのためにもっとメソッドを作ることです。

このコードはここにあります。

class Foo
  attr_accessor :bar
end

このコードと同等です:

class Foo
  def bar
    @bar
  end
  def bar=( new_value )
    @bar = new_value
  end
end

このようなメソッドを自分でRubyに書くことができます。

class Module
  def var( method_name )
    inst_variable_name = "@#{method_name}".to_sym
    define_method method_name do
      instance_variable_get inst_variable_name
    end
    define_method "#{method_name}=" do |new_value|
      instance_variable_set inst_variable_name, new_value
    end
  end
end

class Foo
  var :bar
end

f = Foo.new
p f.bar     #=> nil
f.bar = 42
p f.bar     #=> 42
64
Phrogz

attr_accessorはとても簡単です:

attr_accessor :foo

ショートカットです:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

それはオブジェクトのためのゲッター/セッターに過ぎません

36
efalcao

基本的に、彼らはRubyが持っていない、公にアクセス可能なデータ属性を偽造します。

21
Tyler Eaves

インスタンス変数の取得メソッドと設定メソッドを定義するメソッドです。実装例は次のようになります。

def self.attr_accessor(*names)
  names.each do |name|
    define_method(name) {instance_variable_get("@#{name}")} # This is the getter
    define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter
  end
end
17
Chuck

コードなしの簡単な説明

上記の回答のほとんどはコードを使用しています。この説明は、アナロジー/ストーリーを介して、何も使わずに答えようとします:

外部の関係者は内部CIAシークレットにアクセスできません

  • 本当に秘密の場所、CIAを想像してみましょう。 CIA内の人々を除いて、CIAで何が起こっているのか誰も知らない。つまり、外部の人はCIAの情報にアクセスできません。しかし、完全に秘密の組織を持っているのは良くないので、特定の情報が外部の世界に利用可能になります-CIAが皆にもちろん知って欲しいことだけです: CIAのディレクター、この部門が他のすべての政府部門などと比較して環境に優しいかどうか。その他の情報:例:イラクやアフガニスタンの秘密工作員であるこれらのタイプの物は、おそらく今後150年間は秘密のままでしょう。

  • CIAの外にいる場合は、CIAが一般に公開している情報にのみアクセスできます。または、CIAの用語を使用するには、「クリアされた」情報にのみアクセスできます。

  • CIAがCIAの外部の一般の人々が利用できるようにしたい情報は、次のように呼ばれます。attributes。

読み取りおよび書き込み属性の意味:

  • CIAの場合、ほとんどの属性は「読み取り専用」です。つまり、CIAの関係者がexternalの場合、ask: "CIAのディレクターは誰ですか?"ということです。そして、あなたはまっすぐな答えを得るでしょう。しかし、「読み取り専用」属性でcannotすることは、CIAで変更を加えることです。例えば電話をかけることができず、突然決定キムカーダシアンをディレクターにしたい、またはパリスヒルトンを最高司令官にしたい。

  • 属性が「書き込み」アクセス権を与えた場合、必要に応じて、たとえ外部にいても変更を加えることができます。それ以外の場合、できることは読むことだけです。

    つまり、アクセサーを使用すると、アクセサーが読み取りアクセサーであるか書き込みアクセサーであるかに応じて、外部のユーザーを受け入れない組織に照会したり、変更したりできます。

クラス内のオブジェクトは互いに簡単にアクセスできます

  • 一方、あなたがすでにinside CIAであった場合、カブールでCIAの工作員を簡単に呼び出すことができます。なぜなら、この情報はすでに中にいるので簡単にアクセスできるからです。しかし、あなたがoutside CIAである場合、単にアクセス権が与えられません。彼らが誰であるかを知ることができず(読み取りアクセス権)、ミッションを変更することはできません(書き込みアクセス)。

クラスや、クラス内の変数、プロパティ、メソッドにアクセスする能力についても、まったく同じことが言えます。 HTH!ご質問は、お尋ねください、私は明確にできることを願っています。

14
BKSpurgeon

OOPの概念に慣れている場合は、getterメソッドおよびsetterメソッドに精通している必要があります。 attr_accessorはRubyでも同じことをします。

一般的な方法でゲッターとセッター

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"

セッターメソッド

def name=(val)
  @name = val
end

ゲッターメソッド

def name
  @name
end

RubyのGetterとSetterメソッド

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
13
Ahmed Eshaan

私はこの問題にも直面し、この質問に対してやや長い答えを書いた。これについてはすでにいくつかの素晴らしい答えがありますが、もっと明確にしたいと思っている人は誰でも、私の答えが役立つことを願っています

初期化メソッド

Initializeを使用すると、クラスの新しいインスタンスを作成するたびにコード内の別の行にデータを設定しなくても、インスタンスの作成時にデータをオブジェクトのインスタンスに設定できます。

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

上記のコードでは、InitializeのパラメータにDennisを渡して、initializeメソッドを使用して名前「Denis」を設定しています。 initializeメソッドを使わずに名前を設定したい場合は、次のようにします。

class Person
  attr_accessor :name

  # def initialize(name)
  #     @name = name
  # end

  def greeting
    "Hello #{name}"
  end
end

person = Person.new
person.name = "Dennis"
puts person.greeting

上記のコードでは、オブジェクトの初期化時に値を設定するのではなく、person.nameを使用してattr_accessorセッターメソッドを呼び出して名前を設定します。

この作業をする「初期化」の両方の「方法」は、時間とコード行を節約します。

これが初期化の唯一の仕事です。メソッドとしてinitializeを呼び出すことはできません。インスタンスオブジェクトの値を実際に取得するには、取得メソッドと設定メソッド(attr_reader(get)、attr_writer(set)、およびattr_accessor(both))を使用する必要があります。それらの詳細については下記を参照してください。

ゲッター、セッター(attr_reader、attr_writer、attr_accessor)

ゲッター、attr_reader:ゲッターの全体の目的は特定のインスタンス変数の値を返すことです。この詳細については、以下のサンプルコードをご覧ください。

class Item

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

  def item_name
    @item_name
  end

  def quantity
     @quantity
  end
end

example = Item.new("TV",2)
puts example.item_name
puts example.quantity

上記のコードでは、アイテム「example」のインスタンスでメソッド「item_name」と「Quantity」を呼び出しています。 「puts example.item_name」および「example.quantity」は、「example」に渡されたパラメータの値を返し(または「取得」し)、それらを画面に表示します。

幸運にもRubyにはこのコードをもっと簡潔に書くことを可能にする固有の方法があります。 attr_readerメソッド以下のコードを見てください。

class Item

attr_reader :item_name, :quantity

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

end

item = Item.new("TV",2)
puts item.item_name
puts item.quantity

この構文はまったく同じように機能しますが、それだけで6行のコードが節約されます。 Itemクラスに起因する状態がさらに5つあるかどうかを想像してみてください。コードはすぐに長くなります。

セッター、attr_writer:セッターメソッドと最初に私を交差させたのは、私の目では初期化メソッドと同じ機能を実行するように見えたということです。以下に、私の理解に基づいて違いを説明します。

前述のように、initializeメソッドを使用すると、オブジェクトの作成時にオブジェクトのインスタンスに値を設定できます。

しかし、後でインスタンスを作成した後に値を設定したい場合、または初期化した後に値を変更したい場合はどうしますか?これは、設定メソッドを使用するシナリオです。 IS違い。最初にattr_writerメソッドを使用しているときは、特定の状態を「設定」する必要はありません。

以下のコードは、Itemクラスのこのインスタンスに対して値item_nameを宣言するための設定メソッドの使用例です。コードを自分でテストしたい場合に備えて、値を取得してそれらを画面に表示できるように、引き続きgetterメソッドattr_readerを使用します。

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

以下のコードは、attr_writerを使用してコードをもう一度短くして時間を節約する例です。

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

以下のコードは、作成時にitem_nameのオブジェクト値を設定するためにinitializeを使用している上記のinitializeの例を繰り返したものです。

class Item

attr_reader :item_name

  def initialize(item_name)
    @item_name = item_name
  end

end

item = Item.new("TV")
puts item.item_name

attr_accessor:attr_readerとattr_writerの両方の機能を実行し、あと1行のコードを節約します。

12
Jbur43

私は(私と同じように)新しいRubyists /プログラマーを混乱させるものの一部だと思います:

「インスタンスに特定の属性(名前など)があるだけで、その属性に1つの値をまとめて指定できないのはなぜですか。」

もう少し一般化したものですが、これが私のためにクリックされた方法です:

与えられた:

class Person
end

Person 名前を持つことができるものやその他の属性は定義していません。

だから私たちはその後:

baby = Person.new

…そして彼らに名前をつけよう….

baby.name = "Ruth"

error が出ます、なぜなら、Rubylandでは、Personクラスのobjectは、 "名前"に関連付けられている、またはそれを持つことができるものではないからです...まだ!

しかし、「Personクラスのインスタンス(babyできますは 'name'という属性を持っています。その名前を取得および設定するための構文的な方法はありますが、そうすることは意味があります。」

繰り返しますが、この質問をやや異なるより一般的な観点から叩きますが、これが、このスレッドへの道を見いだすPersonクラスの次のインスタンスに役立つことを願っています。

10
Ben

簡単に言うと、クラスのセッターとゲッターを定義します。

ご了承ください

attr_reader :v is equivalant to 
def v
  @v
end

attr_writer :v is equivalant to
def v=(value)
  @v=value
end

そう

attr_accessor :v which means 
attr_reader :v; attr_writer :v 

クラスの設定メソッドと取得メソッドを定義するのと同じです。

7
Marcus Thornton

単にattr-accessorは指定された属性に対してgettersetterメソッドを作成します

5
Veeru

それを理解するもう1つの方法は、attr_accessorを持つことによってどのエラーコードが排除されるかを把握することです。

例:

class BankAccount    
  def initialize( account_owner )
    @owner = account_owner
    @balance = 0
  end

  def deposit( amount )
    @balance = @balance + amount
  end

  def withdraw( amount )
    @balance = @balance - amount
  end
end

以下の方法があります。

$ bankie = BankAccout.new("Iggy")
$ bankie 
$ bankie.deposit(100)
$ bankie.withdraw(5)

次のメソッドはエラーをスローします。

$ bankie.owner     #undefined method `owner'... 
$ bankie.balance   #undefined method `balance'...

ownerbalanceは、技術的には メソッド ではなく属性です。 BankAccountクラスにはdef ownerdef balanceがありません。もしそうなら、あなたは以下の2つのコマンドを使用することができます。しかし、これら2つの方法はありません。しかし、attr_accessor経由で access メソッドにアクセスするのと同じように、 access attributesにアクセスできます。 それゆえにattr_accessorという言葉 - 。属性。アクセサメソッドにアクセスするのと同じように属性にアクセスします。

attr_accessor :balance, :ownerを追加すると、balanceowner "method"を読み書きできます。今、あなたは最後の2つの方法を使うことができます。

$ bankie.balance
$ bankie.owner
4
Iggy

このモジュールの名前付き属性(名前はsymbol.id2name)を定義し、インスタンス変数(@name)とそれを読み取るための対応するアクセス方法を作成します。属性を設定するためのname =というメソッドも作成します。

module Mod
  attr_accessor(:one, :two)
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]
2
Praveen_Shukla

属性アクセサ、つまりattr_accessorを要約すると、2つの無料のメソッドが得られます。

Javaのように、それらはゲッターとセッターと呼ばれます。

多くの回答が良い例を示しているので、簡単に説明します。

#the_attribute

そして

#the_attribute =

古いRubyドキュメントではハッシュタグ#はメソッドを意味します。クラス名の接頭辞を含めることもできます。MyClass#my_method

1

私はRubyが初めてなので、次のような奇妙な点を理解するだけで対処する必要がありました。将来他の誰かを手助けするかもしれません。結局それは上で述べたように、2つの関数(def myvar、def myvar =)は両方とも@myvarにアクセスするために暗黙のうちに取得しますが、これらのメソッドはローカル宣言によってオーバーライドすることができます。

class Foo
  attr_accessor 'myvar'
  def initialize
    @myvar = "A"
    myvar = "B"
    puts @myvar # A
    puts myvar # B - myvar declared above overrides myvar method
  end

  def test
    puts @myvar # A
    puts myvar # A - coming from myvar accessor

    myvar = "C" # local myvar overrides accessor
    puts @myvar # A
    puts myvar # C

    send "myvar=", "E" # not running "myvar =", but instead calls setter for @myvar
    puts @myvar # E
    puts myvar # C
  end
end
0
Adverbly

属性とアクセサメソッド

属性は、オブジェクトの外部からアクセスできるクラスコンポーネントです。それらは他の多くのプログラミング言語でプロパティとして知られています。それらの値は、object_name.attribute_nameのように、「ドット表記」を使用してアクセスできます。 Pythonや他のいくつかの言語とは異なり、Rubyはインスタンス変数にオブジェクトの外部から直接アクセスすることを許可していません。

class Car
  def initialize
    @wheels = 4  # This is an instance variable
  end
end

c = Car.new
c.wheels     # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>

上記の例では、cはCarクラスのインスタンス(オブジェクト)です。オブジェクトの外部からwheelsインスタンス変数の値を読み出そうとして失敗しました。起こったのは、Rubyがcオブジェクト内でwheelsという名前のメソッドを呼び出そうとしたが、そのようなメソッドが定義されていなかったことです。つまり、object_name.attribute_nameは、オブジェクト内のattribute_nameという名前のメソッドを呼び出そうとします。外部からwheels変数の値にアクセスするには、その名前でインスタンスメソッドを実装する必要があります。これは呼び出されるとその変数の値を返します。これはアクセサメソッドと呼ばれます。一般的なプログラミングのコンテキストでは、オブジェクトの外部からインスタンス変数にアクセスする通常の方法は、getterメソッドおよびsetterメソッドとも呼ばれるアクセサメソッドを実装することです。ゲッターはクラス内で定義された変数の値を外部から読み取ることを可能にし、セッターはそれを外部から書き込むことを可能にします。

次の例では、オブジェクトの外部からwheels変数にアクセスするために、Carクラスにgetterメソッドとsetterメソッドを追加しました。これは、ゲッターとセッターを定義する「Rubyの方法」ではありません。これはgetterメソッドとsetterメソッドが何をするのかを説明するためだけのものです。

class Car
  def wheels  # getter method
    @wheels
  end

  def wheels=(val)  # setter method
    @wheels = val
  end
end

f = Car.new
f.wheels = 4  # The setter method was invoked
f.wheels  # The getter method was invoked
# Output: => 4

上記の例は機能し、同様のコードが他の言語でgetterおよびsetterメソッドを作成するために一般的に使用されています。しかしながら、Rubyはこれを行うためのもっと簡単な方法を提供します:attr_reader、attr_writerおよびattr_acessorと呼ばれる3つの組み込みメソッド。 attr_readerメソッドはインスタンス変数を外部から読み取り可能にし、attr_writerはそれを書き込み可能にし、attr_acessorメソッドは読み取りと書き込みを可能にします。

上記の例は、このように書き換えることができます。

class Car
  attr_accessor :wheels
end

f = Car.new
f.wheels = 4
f.wheels  # Output: => 4

上記の例では、wheels属性はオブジェクトの外側から読み書き可能になります。 attr_accessorの代わりにattr_readerを使用した場合、それは読み取り専用になります。 attr_writerを使用した場合、それは書き込み専用になります。これらの3つのメソッドは、それ自体が取得メソッドと設定メソッドではありませんが、呼び出されると、取得メソッドと設定メソッドを作成します。それらは動的に(プログラム的に)他のメソッドを生成するメソッドです。これはメタプログラミングと呼ばれます。

Rubyの組み込みメソッドを採用していない最初の(長い)例は、getterメソッドとsetterメソッドで追加のコードが必要な場合にのみ使用してください。たとえば、セッターメソッドは、インスタンス変数に値を代入する前に、データを検証したり、計算を実行したりする必要があります。

Instance_variable_getおよびinstance_variable_set組み込みメソッドを使用して、オブジェクトの外部からインスタンス変数にアクセス(読み取りおよび書き込み)することができます。しかしながら、カプセル化を迂回することはあらゆる種類の混乱を招く傾向があるので、これはめったに正当化できず、通常悪い考えです。

0
BrunoFacca