すばらしい質問です。残念ながら、あなたはうさぎの穴を飛び降りたばかりですが、それはあなたが本当の複雑さを理解し始めるために最終的にルビーに陥らなければならないものです。
最初の質問ですが、$
-prefixedグローバル変数についてです。それらは本当にグローバルです:
def mk_foo() $foo ||= "foo"; end
$foo # => nil
mk_foo # => "foo"
$foo # => "foo"
mk_foo.object_id # => 70299647799620
$foo.object_id # => 70299647799620
ご覧のとおり、がメソッド$foo
内で定義されているmk_foo
場合、それはグローバルスペースで定義されており、どこからでもアクセスできます。
class CanSeeFoo
def see_foo() $foo; end
end
CanSeeFoo.new.can_see_foo
# => "foo"
CanSeeFoo.new.can_see_foo.object_id
# => 70299647799620
クラス変数の質問に関しては、ここからウサギの穴が始まります。まず、@@
-prefixed変数は「クラス変数」と@
呼ばれ、-prefixed変数は「インスタンス変数」と呼ばれるというのは正しいことです。
クラス変数は、定義するクラスのすべてのサブクラス(継承ツリーのすべてのサブレベル)で静的です。ここでの意味は、サブクラスがクラス変数を変更すると、関連するすべてのサブクラスから定義クラスまでが変更されるということです。
class A; end
class B < A; @@foo = "foo"; end
B.class_variable_get(:@@foo) # => "foo"
A.class_variable_get(:@@foo)
# => raises NameError "uninitialized class variable @@foo in A"
class C < B; end
C.class_variable_get(:@@foo) # => "foo"
class D < C
def self.change_foo(); @@foo = "bar"; end
def change_foo(); @@foo = "baz"; end
end
D.class_variable_get(:@@foo) # => "foo"
class E < D; end
E.class_variable_get(:@@foo) # => "foo"
D.change_foo # => "bar"
D.class_variable_get(:@@foo) # => "bar"
E.class_variable_get(:@@foo) # => "bar"
C.class_variable_get(:@@foo) # => "bar"
B.class_variable_get(:@@foo) # => "bar"
D.new.change_foo # => "baz"
D.class_variable_get(:@@foo) # => "baz"
E.class_variable_get(:@@foo) # => "baz"
C.class_variable_get(:@@foo) # => "baz"
B.class_variable_get(:@@foo) # => "baz"
A.class_variable_get(:@@foo)
# => raises NameError "uninitialized class variable @@foo in A"
クラス変数とインスタンス変数へのアクセスに関しては、アクセサーを使用せずに、#instance_variable_get
または::class_variable_get
アクセサーが定義されるまで、どちらにもアクセスできません。現在、rubyにはインスタンス変数にアクセサーを定義するためのメソッドしかありませんが、クラス変数に適切なメソッドを定義するのは簡単です。
class A
@@foo = "foo"
# the second argument `true` adds the writer method `#bar=`
attr :bar, true
def self.foo(); @@foo; end
def self.foo=(v); @@foo = v; end
def initialize()
@bar = "bar"
end
end
class B < A; end
A.foo # => "foo"
B.foo = "foobar"
A.foo # => "foobar"
B.foo # => "foobar"
a = A.new
a.bar # => "bar"
a.bar = "baz"
a.bar # => "baz"
a.foo
# => raises NoMethodError: undefined method `foo' for #<A:0x ...
属性アクセサーメソッドは、Rubyコアドキュメントで確認できます:http ://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr 。また、ActiveSupport(http://rubygems.org/gems/activesupport)にはcattr
、クラス変数アクセサーを定義するための""メソッドがありますhttp://api.rubyonrails.org/v3.2.5/classes/Class.html#method-i-cattr_accessor。
それは単純なことです。次のステップは、「eigenclass」または「metaclass」( Wikipedia: Metaclass)とも呼ばれる「シングルトンクラス」を理解することです(ルビーのすべては、クラスおよびモジュール構造を含むオブジェクトであることに注意してください)。ここでは、Yehuda Katzによる優れた投稿を紹介します:Rubyでのメタプログラミング:それはすべて自己についてです、そして別のスタックオーバーフローの質問:クラス<<Rubyの自己イディオム。
プレビューとして:シングルトンクラス(シングルトンデザインパターンと混同しないでください)を使用すると、特定のクラスまたはモジュールのメソッドとインスタンスデータにアクセスできます。関連するドキュメントについては、コアドキュメントを参照してください:http ://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class
class A; end
class B < A;
class << self
def foo() @foo end
def foo=(v) @foo = v; end
end
end
B.foo = "foo"
class C < B; end
A.foo
# => raises NoMethodError: undefined method `foo' for A:Class
B.foo # => "foo"
C.foo # => nil
B.foo = "baz"
B.foo # => "baz"
C.foo # => nil
C.foo = "foo"
C.foo # => "foo"
B.foo # => "baz"
最後に、 Ruby-Coreドキュメントを利用することを忘れないでください。上記を理解するのに最も役立つのは次のとおりです。