2016-08-31 11 views
3

私はJavaからRubyに移行し、Rubyスコープを理解しようとしています。Rubyのクラス変数はJavaの静的変数に似ていますか?

Javaでは、クラス変数は静的変数と同じように動作するようです。この解釈は正しいのでしょうか?もしそうなら、Rubyのグローバル変数は、Javaのpublic static変数と同じですか?

+0

私はJavaに精通していませんが、[this](http://stackoverflow.com/a/2086837/4001311)答えが見つかりました。 –

+1

アドバイス:あなたが知っている言語と学習している言語との類似点を探し出すことは致命的な結果に終わり、結果的に新しい言語の非慣習的で醜いコードになることがあります。私はむしろ特定の問題に焦点を当て、どのようにそれらをさまざまな言語で扱うかを考えます。 Javaの静的変数で通常解決される1つの問題を選択し、Rubyで正しい解決方法を尋ねます。答えはクラス変数かもしれませんが、しばしば無関係なものになることがよくあります。 –

+0

いいえ、私は同じような直感を持っていたので、私はあなたを感じます。 – Casey

答えて

2

RubyとJavaの間にはオブジェクト指向であることが多いため類似点はたくさんありますが、そのファミリツリーは異なります。 RubyはSmalltalkに非常に頼りになりますが、JavaはC++という学校から継承します。

ここでの違いは、Rubyのpublic/private/protectedの概念はかなり弱く、ルールよりも多くの提案であり、静的メソッドや定数のようなものは言語の構文よりもパターンが多いことです。

大域変数は非常に大きく眉をひそめています。自由に使用すると、混乱の原因となります。 Rubyの方法は、名前空間のものにある:このモジュールのような

$ugly_global = 0 # Not recommended, could conflict with other code 
        # Ownership of this variable isn't made clear. 

$ugly_global += 1 # Works, but again, it's without context. 

module UglyCounter # Defines a module/namespace to live in 
    def self.current # Defines a clear interface to this value 
    @counter ||= 0 # Initializes a local instance variable 
    end 

    def self.current=(v) # Allow modification of this value 
    @counter = v.to_i # A chance to perform any casting/cleaning 
    end 
end 

UglyCounter.current += 1 # Modifies the state of a variable, but 
          # the context is made clear. 

さえ薄い層があなたにこの変数からの読み出し/書き込み動作をインターセプトし、動作を変更することができます。たぶん、特定の値にデフォルト値を設定したり、値を正規化された形式に変換したりすることができます。裸の世界では、このコードをどこでも繰り返す必要があります。ここでそれを統合することができます。

クラス変数はまったく別のものです。また、このクラスのクラスとインスタンス間でデータを共有することは面倒なことがあるため、避けてください。彼らは2つの異なる文脈であり、分離は尊重されるべきです。

class MessyClass 
    @@shared = 0 

    def counter 
    @@shared 
    end 

    def counter=(v) 
    @@shared = v 
    end 
end 

これは、共有クラスレベルのインスタンス変数を使用する方法のかなり大まかな取り組みです。ここで問題となるのは、各インスタンスがクラス・コンテキストをバイパスして直接変更することです。つまり、そのクラスは無力です。これは根本的に失礼であり、インスタンスはその権限を過度に拡張しています。より良いアプローチはこれです:静的クラスメソッドが自動的にインスタンスの範囲で利用可能になる

class CleanerClass 
    def self.counter 
    @counter ||= 0 
    end 

    def self.counter=(v) 
    @counter = v.to_i 
    end 

    # These are reduced to simple bridge methods, nothing more. Because 
    # they simply forward calls there's no breach of authority. 
    def counter 
    self.class.counter 
    end 

    def counter=(v) 
    self.class.counter = v 
    end 
end 

多くの言語では、これは、Rubyには当てはまりません。ブリッジ/プロキシ/デリゲートメソッドを記述する必要があります。ここで使用する用語は、使用しているものによって異なります。

+0

「self」の値の違いについても言及する価値があります。 –

+0

良い点。 「自己」は、あなたがあなたのやり方から外れて再結合しない限り、常にあなたがいる文脈ですから、それもあります。 – tadman

+1

AFAIKクラス変数の大きな問題は、インスタンス間で情報が共有されているわけではなく(結局のところ、クラスメソッドの方法では解決できませんが)、それらは[予期しない方法でお互いにボウルすることができます] archive.oreilly.com/pub/post/nubygems_dont_use_class_variab_1.html)。 – Casey

2

私はJavaに精通していませんが、私はRubyの用語で説明することができます。

Rubyでは、クラス変数の前に変数名@@があります。それはあなたが思うように行動しません。クラス変数が作成されると、それはすべてのサブクラス間で共有されます。

グローバル変数の場合は、変数名の前に$があります。それはまるでそれがそうであるように聞こえる、それはグローバルであり、どこにでもアクセスすることができます。

両方の変数はRubyではお勧めできません。名前の前に@というインスタンス変数を使用して、必要な処理を行うことができます。オブジェクトに固有です。あるオブジェクトに宣言すると、別のオブジェクトには表示されません。

これがこれをクリアすることを願っています。

+0

また、ivarsは_classオブジェクトに設定することもできます。 –

2

重要な違いの1つは、静的メソッドとインスタンス変数がJavaではできない方法で、クラスメソッドとインスタンス変数がRubyでやり取りする方法です。

tadmanの答えは、このコードが含まれています。世界のジャワ(およびC#の)プログラマに

class CleanerClass 
    def self.counter 
    @counter ||= 0 
    end 

    def self.counter=(v) 
    @counter = v.to_i 
    end 
end 

それが動作してはならないように、このコードが見えます。結局のところ、そのモデルでは、静的メソッドからインスタンス変数にアクセスするというアイデアはインコヒーレントであり(コンパイルもされません)全体のポイントは、あなたがインスタンスを持っていないということです!

しかし、Rubyでは、すべてのクラス定義自体がClass型のインスタンスです。 @counterへの参照は、実際にClassオブジェクトにインスタンス変数CleanerClassを作成します。それを@@counterに変更すると、あなたが好きなように思えるかもしれませんが、あなたが宣言したクラスだけでなく、他のクラスも汚染されます。

関連する問題