2017-05-08 8 views
2

Rubyプログラムでの作業インスタンス変数からクラス変数への状態データの移動を探していましたが、インスタンス変数は自動化されていますが、初期化せずに読み込もうとすると自動的にnilに初期化されています)、クラス変数はありません。これは私にとって非常に矛盾しています(Rubyのほとんどの構文は非常に一貫しています)。Rubyのクラス変数は自動化されていませんか?

サンプルプログラム:@idが初期化されなかった場合

class Test 
    def id 
    @id.to_i 
    end 
    def id=(i) 
    @id = i 
    end 
    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid #=> 1 
puts t.nextid #=> 2 

その場合、Test::idを呼び出すには、Rubyが(その後、私は0を得るためにそれをto_inilにそれを自動vivifyます。

今、私は私が実行しているIDがTestインスタンス間で共有されたくないので、私はこのようにそれを書き換えることを決定:

class Test 
    def id 
    @@id.to_i 
    end 
    def id=(i) 
    @@id = i 
    end 
    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid 
puts t.nextid 

同じように機能するなら、私は思ったが、何も:

NameError: uninitialized class variable @@id in Test 

しかし、この回避策が動作します(!?):

class Test 
    def id 
    (@@id ||= 0).to_i 
    end 
    def id=(i) 
    @@id = i 
    end 
    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid #=> 1 
puts t.nextid #=> 2 

(0に怠惰な初期化を行った後、付与されましたto_iを削除できますが、一貫性のために残しました)。

Rubyは「遅延初期化」を理解し、魔法がNameErrorを投げていないために、必要に応じてそれを扱うように見えます - ||=はおそらくx = x || valにだけ糖衣構文であるにも関わらず(ところで、クラス変数をINITINGを求めるためのおかげで動作しません)。

どうしてですか?

+3

'X || = val'は、x 'とちょっと同じです|| x = x ||ではなく、x = val'でなければなりません。 val'。また、あなたのコードでは、なぜインスタンスメソッドがクラス変数を設定したいのですか? –

+0

あなたはどのRubyバージョンをテストしていますか?私はruby-2.2で2番目のケースを試しました。2、私はNoMethodError:未定義のメソッド '+'を返します。これは 'NameError:初期化されていないクラス変数@@ id'の代わりにnil:NilClass'です。 – fangxing

+0

@fangxing:Rubyのバージョンに依存しないと思います。私はそれが質問のタイプミスだと言いたい。 'self.id = id + 1'を使って、上記のエラーを得ることができます。 –

答えて

3

クラス変数の初期化

@anilですが@@aNameErrorである理由はここにpossible explanationです。

しかし、あなたはクラス変数を使用したい場合、あなたはクラスの内部ではなく、インスタンスメソッド内でそれらを初期化する必要があります。

class Test 
    @@id = 0 

    def id 
    @@id 
    end 

    def id=(i) 
    @@id = i 
    end 

    def nextid 
    self.id = id + 1 
    end 
end 

t = Test.new 
puts t.nextid 
puts t.nextid 

それはのインスタンスsetterメソッドを持つようにあまり意味がありませんのでご注意くださいクラス変数。インスタンスメソッドとクラス変数を混​​合避けるため

クラスのインスタンス変数

、あなたは"class instance variable"でクラスレベルですべてのものを定義することができます。これは、クラスレベルで定義されているインスタンス変数です:

class Test 
    @id = 0 
    class << self 
    def id 
     @id 
    end 

    def id=(i) 
     @id = i 
    end 

    def nextid 
     self.id = id + 1 
    end 
    end 
end 

puts Test.id 
# 0 
puts Test.nextid 
# 1 
puts Test.nextid 
# 2 

それはあなただけattr_accesorを使用することを意味します:

​​
+0

ああ、私の謝罪。私は実際にその行を読んでいない、instaトリガーされた。私には恥ずべき! –

+0

"また、あなたは、|| =クラス変数では機能しませんが、明らかに間違っていると主張しています" - 私は具体的にそれを主張しなかった、OPを読んでください。問題は*なぜ*クラス変数のために働くのですか?なぜなら "read before write"はそうではありませんでした。 – Guss

+0

ありがとうございますが、私が指摘しなかったように、私は解決策には興味がありません(私はすでに、醜い解決策ではあるが、それを提示したように)。 。あなたが指摘した「可能な説明」は、基本的に「次のエッジケースでは理にかなっています」というものです。これはほとんど設計上の理由ではありません。 – Guss

関連する問題