web-dev-qa-db-ja.com

クラスメソッドでのインスタンス変数の使用-Ruby

次のようなクラスがあり、インスタンス変数(配列)を使用して、多くのメソッドパラメーターを使用しないようにしました。

期待どおりに動作しますが、それは良い習慣ですか?実際、それが機能するとは期待していませんが、他の言語ではクラスメソッドが静的メソッドとして機能していないと思います。

class DummyClass
  def self.dummy_method1
    @arr = []
    # Play with that array
  end

  def self.dummy_method2
    # use @arr for something else
  end
end
51
tackleberry

インスタンス変数がRubyのクラスで機能する理由は、Rubyクラスareインスタンス自体(クラスのインスタンス Class )。_DummyClass.class_を調べて自分で試してみてください。C#の意味で「Ruby」には「静的メソッド」はありません。 (または継承されて)あるインスタンスで呼び出され、したがって、呼び出し先で使用可能なインスタンス変数にアクセスできます。

DummyClassはインスタンスであるため、独自のインスタンス変数を持つことができます。クラスへの参照がある限り、これらのインスタンス変数にアクセスすることもできます(クラス名は定数であるため、常にそうする必要があります)。どの時点でも、::DummyClass.instance_variable_get(:@arr)を呼び出して、そのインスタンス変数の現在の値を取得できます。

それが良いことかどうかについては、メソッドに依存します

_@arr_が論理的にインスタンス/クラスDummyClassの「状態」である場合、インスタンス変数に格納します。 _@arr_が_dummy_method2_で操作上のショートカットとしてのみ使用されている場合は、引数として渡します。インスタンス変数アプローチが使用される例を示すために、RailsのActiveRecordを検討してください。これを行うことができます:

_u = User.new
u.name = "foobar"
u.save
_

ここで、ユーザーに割り当てられている名前は、ユーザーに合法的に存在するデータです。 _#save_呼び出しの前に、「この時点でユーザーの名前は何ですか」と尋ねた場合、「foobar」と答えます。内部を深く掘り下げると(非常に深く掘り下げて多くのメタプログラミングを掘り下げることになりますが、まさにこのためにインスタンス変数を使用していることがわかります)。

私が使用した例には、2つの個別のパブリック呼び出しが含まれています。呼び出しが1回だけ行われたにもかかわらず、インスタンス変数がまだ使用されている場合を見るには、 _#update_attributes_ のActiveRecord実装を見てください。メソッド本体は単純にload(attributes, false) && saveです。 _#save_のようなsaveの本体にあるにもかかわらず、_UPDATE users SET name='foobar' WHERE id=1;_に引数(新しいnameなど)が渡されないのはなぜですか?名前のようなものはインスタンスに属する情報だからです。

逆に、インスタンス変数を使用しても意味がない場合を見ることができます。 _#link_to_if_ の実装を見てください。これは、_#link_to_によって通常受け入れられる引数とともに、ブール値のような引数(通常はソースコードの式)を受け入れるメソッドです。リンク先のURL。ブール条件が真である場合、残りの引数を_#link_to_に渡して呼び出す必要があります。ここで呼び出しコンテキスト(レンダラー)がインスタンスにその情報を含むとは言わないので、ここにインスタンス変数を割り当てることはあまり意味がありません。レンダラー自体には「リンクするURL」がないため、インスタンス変数に埋め込まないでください。

70
Steven

これらはクラスインスタンス変数であり、Rubyでは完全に正当なものです。クラスもオブジェクト(クラスのインスタンス)なので、インスタンス変数もあります。

注目すべきことは、各サブクラスが独自のクラスインスタンス変数のセットを持っていることです(これらはすべて異なるオブジェクトであるため):DummyClassをサブクラス化すると、サブクラスのクラスメソッドは@arr

クラス変数(@@foo)はもちろん逆です:クラス階層全体が同じクラス変数を共有します。

22