35

ruby の学習を始めたばかりで、@instace_variableと を使用して宣言された属性の違いがわかりませんattr_accessor

次の 2 つのクラスの違いは何ですか。

class MyClass  
  @variable1 
end

class MyClass
  attr_accessor :variable1
end

オンラインでたくさんのチュートリアルを検索しましたが、誰もが異なる表記法を使用しています.Rubyバージョンと何か関係がありますか? StackOverflow でいくつかの古いスレッドも検索しました

Rubyのattr_accessorとは何ですか?
これら 2 つの Ruby クラス初期化定義の違いは何ですか?

しかし、それでも私はどのように使用するのが最善かを理解することができません。

4

6 に答える 6

58

インスタンス変数は、それが入っているオブジェクトの外では見えません。ただし、 を作成するattr_accessorと、インスタンス変数が作成され、オブジェクトの外部で表示 (および編集可能) されます。

インスタンス変数を使用した例 (not attr_accessor)

class MyClass
  def initialize
    @greeting = "hello"
  end
end

m = MyClass.new
m.greeting #results in the following error:
  #NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 @greeting="hello">

使用例attr_accessor

class MyClass
  attr_accessor :greeting

  def initialize
    @greeting = "hello"
  end
end

m2 = MyClass.new
m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object
m2.greeting #=> "bonjour"   <-- didn't blow up as attr_accessor makes the variable accessible from outside the object

それが明確になることを願っています。

于 2012-10-16T22:26:02.603 に答える
30

インスタンス変数は、クラスの外では直接見ることができません。

class MyClass
  def initialize
    @message = "Hello"
  end
end

msg = MyClass.new
@message
#==> nil   # This @message belongs to the global object, not msg
msg.message
#==> NoMethodError: undefined method `message'
msg.@message
#==> SyntaxError: syntax error, unexpected tIVAR

これで、いつでもこれを行うことができます:

msg.instance_eval { @message }

または、次のように直接変数を要求します。

msg.instance_variable_get :@message

しかし、それは厄介で、一種の不正行為です。他の人のクラスをいじることは教育的かもしれませんが、信頼できる結果を得るためにクライアント コードでそれを行う必要はありません。したがって、クライアントにこれらの値を表示させたい場合は、上記の手法をクライアントに使用させないでください。代わりに、値を明示的に公開するメソッドを定義します。

class MyClass
  def message 
    return @message
  end
end
msg.message
# ==> "Hello"

頻繁にそうしたいので、Ruby はそれを簡単にするためのショートカットを提供します。以下のコードは、上記のコードとまったく同じ結果になります。

class MyClass
  attr_reader :message
end

これは新しいタイプの変数ではありません。メソッドを定義する簡単な方法です。メソッドが追加されmsg.methodsていることがわかりますmessage

では、部外者がインスタンス変数の値を表示するだけでなく、値を変更できるようにしたい場合はどうすればよいでしょうか? そのために=は、名前に a を使用して、割り当て用の別のメソッドを定義する必要があります。

class MyClass
  def message=(new_value)
    @message = new_value
  end
end
msg.message = "Good-bye"
msg.message
# ==> "Good-bye"

ここでは代入演算子が半魔法的であることに注意してください。msg.messageと の間にスペースがありますが=、Ruby はmessage=メソッドを呼び出すことを認識しています。などの組み合わせ演算子+=は、メソッドへの呼び出しもトリガーします。

繰り返しますが、これは一般的な設計であるため、Ruby はそのためのショートカットも提供しています。

class MyClass
  attr_writer :message
end

ここで、attr_writer単独で使用すると、変更できるが表示されない属性が得られます。それが必要な奇妙な使用例がいくつかありますが、ほとんどの場合、部外者が変数を変更できるようにする場合は、変数も読み取れるようにする必要があります。attr_readeranと an の両方を宣言する必要はなく、次のattr_writerように両方を一度に宣言できます。

class MyClass
  attr_accessor :message
end

繰り返しますが、これは、クラスの外部からインスタンス変数を取得できるようにするメソッドを定義するための単なるショートカットです。

于 2012-10-16T22:40:46.577 に答える
9

attr_accesorインスタンス変数を読み書きするメソッドを提供します。インスタンス変数は外界から隠されるように設計されているため、それらと通信するには attr _ibuteアクセサーメソッドが必要です。

于 2012-10-16T22:37:35.847 に答える
3

OOPS には、カプセル化と呼ばれる概念があります。つまり、オブジェクトの内部表現は、通常、オブジェクトの定義の外では見えません。オブジェクトの「それ自体」だけが、自身の内部状態をいじることができます。外の世界はできません。

すべてのオブジェクトは通常、その状態と動作によって定義されます。Ruby では、インスタンス変数はオブジェクトの内部状態または状態と呼ばれ、OOPS によれば、状態は他のオブジェクトからアクセスされるべきではなく、そうすることでカプセル化を順守します。

元:class Foo def initialize(bar) @bar = bar end end

上記では、クラス Foo を定義し、initialize メソッドでインスタンス変数 (属性) または (プロパティ) を初期化しました。new メソッドを使用して新しい ruby​​ オブジェクトを作成すると、内部で initialize メソッドが呼び出され、メソッドが実行されると @bar インスタンス変数が宣言および初期化され、オブジェクトの状態として保存されます。

すべてのインスタンス変数には独自の内部状態があり、オブジェクト自体に固有です。クラスで定義するすべてのメソッドは、メソッドの定義と目的に従ってオブジェクトの内部状態を変更します。ここで、initialize メソッドは、新しいインスタンス変数の作成など、同じことを行います。

var object = Foo.new(1)
#<Foo:0x00000001910cc0 @bar=1>

バックグラウンドで、ruby はインスタンス変数 (@bar =1) を作成し、その値をオブジェクトの状態としてオブジェクト 'object' 内に格納しました。「instance_variables」メソッドで確認できます。そのメソッドは、オブジェクトの現在の状態に応じて、オブジェクトのすべてのインスタンス変数を含む配列を返します。

object.instance_variables
#[
     [0]: @bar
 ]

上記の「@bar」インスタンス変数を見ることができます。これは、オブジェクトで initialize メソッドを呼び出したときに作成されます。この '@bar' 変数は、デフォルトでは表示 (非表示) されるべきではないため、オブジェクト以外のオブジェクトの外部から、内部から他のユーザーに表示されることはありません。ただし、オブジェクトは独自の内部状態をいじることができます。これは、値を表示または変更できることを意味します。これら 2 つは、クラスに新しいインスタンス メソッドを作成することで実行できます。

@bar 変数を呼び出して確認したい場合、デフォルトではオブジェクトの状態を確認できないため、エラーが発生します。

show = object.bar
#NoMethodError: undefined method `bar' for #<Foo:0x00000001910cc0 @bar=1>
#from (irb):24
#from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in `<main>'

しかし、変数には 2 つのメソッドでアクセスできます。これら 2 つのメソッドはセッター メソッドとゲッターメソッドと呼ばれ、オブジェクトが内部状態 (インスタンス変数/属性/プロパティ) をそれぞれ表示または変更できるようにします。

class Foo
  def bar
    @bar
  end

  def bar=(new_bar)
    @bar = new_bar
  end
end

getter(bar) および setter(bar=) メソッドを定義しました。任意の名前を付けることができますが、内部のインスタンス変数は、値を表示または変更するインスタンス変数と同じである必要があります。セッターとゲッターは、ある意味で OOPS の概念に違反していますが、非常に強力なメソッドでもあります。

クラスを再度開いて定義することで 2 つのメソッドを定義すると、メソッドでオブジェクトを呼び出すと、インスタンス変数 (ここでは @foo) を表示し、その値も変更できます。

object.bar
1

object.bar=2
2

object.bar
2

ここでは、@bar の値を返す bar メソッド (getter) を呼び出し、引数として new_value を指定した bar= メソッド (setter) を呼び出し、インスタンス変数 (@bar) の値を変更します。 bar メソッドを呼び出してもう一度見てください。

Ruby には、セッター メソッドとゲッター メソッドの両方を組み合わせたattr_accessorというメソッドがあり、クラス内のメソッド定義の上に定義します。attr_* メソッドは、メソッド (setter および getter) を作成するためのショートカットです。

class Foo
  attr_accessor :bar
end

シンボル (:bar) を attr_accessor メソッドの引数として指定する必要があります。このメソッドは、指定されたシンボル名としてメソッド名を使用して、setter メソッドと getter メソッドの両方を内部的に作成します。

getter メソッドのみが必要な場合は、attr_reader :bar を呼び出すことができます。setter メソッドのみが必要な場合は、attr_writer :bar を呼び出すことができます。

attr_accessor は attr_writer と attr_reader メソッドの両方を作成します

コンマで区切られた attr_* メソッドに必要な数のインスタンス変数を指定できます

class Foo
  attr_writer :bar
  attr_reader :bar
  attr_accessor :bar, :baz
end
于 2018-03-22T06:53:36.350 に答える
1

はメソッドを定義しているためattr_accessor、クラスの外から呼び出すことができます。A@variableは、クラス内からのみアクセスできます。

于 2014-07-31T22:24:23.397 に答える