2
class Something
    @@variable = 'Class variable'

    def give_me
        @@variable
    end
end

class OtherThing
    @variable = 'Instance variable with an interface'

    class << self
        attr_accessor :variable
    end

    def give_me
        self.class.variable
    end
end

p Something.new.give_me
p OtherThing.new.give_me

私が知りたいのは、どちらを使用すればよいですか? それぞれのメリットとデメリットは?

クラス変数は次のとおりです。

  1. インターフェイスを作成しない限り非公開
  2. 継承間で共有
  3. 短く書く

クラスインスタンス変数は次のとおりです。

  1. パブリック。アクセスするにはインターフェイスを使用する必要があるため
  2. 継承間で共有されませんが、継承時に nil に設定されます
  3. 書くのが長くなる

他に何を念頭に置く必要がありますか?

4

4 に答える 4

3

私は最近、 ActiveSupport define を発見しましclass_inheritable_accessorた。これは、オブジェクトが継承間で共有されず、サブクラス化時に変数のデフォルト値を持つことができるという利点を備えた、クラス インスタンス変数と同じことを行います。

class Foo
  class_inheritable_accessor :x, :y
end

Foo.x = 1

class Bar < Foo
end

Bar.x #=> 1
Bar.x = 3
Bar.x #=> 3
Foo.x #=> 1

詳細はこちら

完全を期すために: 提示された 2 つのオプションのうち、私はクラス インスタンス変数を使用することを好みます。

于 2011-08-16T05:15:35.347 に答える
3

Ruby では決してクラス変数を使用しないでください。それらは継承に問題を引き起こします。代わりに常にクラス インスタンス変数を使用してください。

于 2011-08-16T13:52:50.067 に答える
1

クラスレベルでインスタンス変数を宣言するオプションもあります。

class Foo
    @bar = 'baz'

    def Foo.print
        puts @bar
    end
end

全体として、継承間共有モデルは非常に驚くべきものであり、自明ではないことが多いため、クラス変数は避けたいと思います。正直なところ、完全にグローバルではないことを除けば、彼らが実際にどのようなユーティリティを提供しているかはわかりません。

「スコープ付き」グローバル変数が必要な場合は、アクセサーを備えたクラスレベルのインスタンス変数を使用します。カプセル化を維持しながら、継承の「サプライズ」を回避します。

于 2011-08-16T00:20:44.180 に答える
1

クラス インスタンス変数は、一般に、クラス変数よりも便利で意外性が低いため、おそらくそれらを使用する必要があります。

ここで、StackOverflow に関する Ruby の回答に期待される、耐え難いほど詳細にいくつかのことを説明します。

クラス インスタンス変数を宣言または参照するには、クラス スコープ内にいて、単一の @ 記号を使用する必要があります。これにより、そのクラスのシングルトン クラス インスタンスに変数が配置されます。

残念ながら、クラス スコープ内でキーワードを使用すると、メソッドはそのクラスのインスタンス メソッドdefのリストに配置され、インスタンス スコープ内で実行されるため、@ 記号変数はそれらが存在するインスタンス上にあります。 .

代わりに、インスタンスではなく、クラスでメソッドを定義する必要があります。これが実際に意味することは、これらのメソッドがクラス オブジェクトシングルトン クラスインスタンス メソッドのリストにあるということです。(ふぅ!)

要約すると、クラス object のシングルトン クラスでメソッドを切り替えて定義するには、少なくとも 4 つのイディオムがありますFoo

class Foo
  @a, @b, @c, @d = 1, 2, 3, 4

  # 1. pass the target to def
  def Foo.a
    @a
  end

  # 2. pass the target to def, relying on the fact that self 
  # happens to be the class object right now
  def self.b
    @b
  end

  # switch from class scope to singleton class scope
  class << self

    # 3. define a plain accessor in singleton class scope
    def c
      @c
    end

    # 4. use a macro to define an accessor
    attr_reader :d
  end

end

p [Foo.a, Foo.b, Foo.c, Foo.d]
#=> [1, 2, 3, 4]

(考慮に入れれば、これを行う方法はおそらく他にも 6 つ以上ありますがclass_evaldefine_method今のところはそれで満足するはずです。:-))

最後に 1 つ: クラス インスタンス変数は、それらが定義されているクラスを介してのみ使用できます。サブクラスから (またはサブクラスを介して) これらのメソッドのいずれかを呼び出そうとすると、メソッドは実行されますが、@ 変数はすべて nil になりselfます。

class Bar < Foo
end

p [Bar.a, Bar.b, Bar.c, Bar.d]
#=> [nil, nil, nil, nil]
于 2011-09-28T02:09:34.970 に答える