49

私はプログラミングに不慣れです。今、私はRubyを勉強しています。私の理解では、グローバル変数はグローバル名前空間で定義されています(したがって、クラスや関数の外部で定義されています)。私は何かを読んでいて、グローバル変数の$前に符号があると書かれています。どういう意味ですか?関数またはクラスを定義し、グローバル変数を参照したい場合(たとえば、そうだとしましょうedmund = 123)、次のように参照する必要があり$edmundますか?

それで:

edmund = 123
def my_function()
  456 + $edmund
end

また、クラス変数(で始まるもの@@)は、インスタンス変数()のように、 ?@を介して呼び出すことでアクセスできます。Class.classvariable彼らの目的は何ですか?

4

4 に答える 4

53

グローバルスコープは、プログラム全体をカバーするスコープです。グローバルスコープは、最初のドル記号($)文字で認識できるグローバル変数によって利用されます。それらはどこでも利用可能であり、独自のグローバル変数を作成することは、特に初心者のプログラマーにとっては魅力的です。しかし、それらは必ずしも良い考えではありません。

$gvar = "I'm a global!"
class C
    def examine_global
        puts $gvar
    end
end

c = C.new
c.examine_global # I'm a global!

クラス変数は、たとえば@@varの2つの記号で始まります。それらの名前にもかかわらず、クラス変数はクラススコープではありません。むしろ、それらはクラス階層スコープです。最も単純なクラス変数の背後にある考え方は、クラスとそのクラスのインスタンスの間で共有され、他のオブジェクトには表示されないストレージメカニズムを提供することです。

class Parent
    @@value = 100
end

class Child < Parent
    @@value = 200
end

class Parent
    puts @@value
end

印刷されるのは200です。ChildクラスはParentのサブクラスです。つまり、ParentとChildは同じクラス変数を共有します。つまり、同じ名前の異なるクラス変数ではなく、同じ実際の変数です。子の@@valueに割り当てるときは、階層全体で共有される唯一の@@ value変数を設定します。つまり、親と子、およびそれらのいずれかのその他の子孫クラスによって共有されます。


そして、正当な理由を認めるために-この説明は、Rubyについて学ぶのに最適なリソースの1つであるDavidABlackによる「TheWellGroundedRubyist」からのものです。

于 2012-08-24T16:56:52.793 に答える
10

すばらしい質問です。残念ながら、あなたはうさぎの穴を飛び降りたばかりですが、それはあなたが本当の複雑さを理解し始めるために最終的にルビーに陥らなければならないものです。

最初の質問ですが、$-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ドキュメントを利用することを忘れないでください。上記を理解するのに最も役立つのは次のとおりです。

于 2012-08-24T18:51:18.643 に答える
4

ドル記号は変数名の一部であるため、次のように宣言する必要があります。

$edmund = 123

@これは、インスタンス変数とクラス変数の場合と同じです。名前はまたはで始まります@@

于 2012-08-24T16:17:52.330 に答える
0

これらの記事をチェックしてください:

http://www.rubyist.net/~slagell/ruby/globalvars.html

Rubyでグローバル変数または定数値をどのように使用しますか?

于 2012-08-24T16:18:54.630 に答える