2009-06-25 11 views
64

私は次のようになりますプログラムがあります。$offsetの使用は少し奇妙なようだRubyでグローバル変数や定数をどのように使用しますか?

$offset = Point.new(100, 200); 

def draw(point) 
    pointNew = $offset + point; 
    drawAbsolute(point) 
end 

draw(Point.new(3, 4)); 

を。

C言語では、関数の外に何かを定義すると、自動的にグローバル変数になります。なぜRubyでは$offsetにする必要がありますが、offsetにすることはできませんが、それでもグローバルにすることはできますか?それがoffsetなら、それはローカルですか?しかし、それは非常にグローバルな感じがするので、どこにローカル。

上記のコードを書く良い方法はありますか? $offsetの使用は、最初は少し醜いかもしれません。


アップデート:私はclass定義内のこのオフセットを置くことができますが、2またはいくつかのクラスは、この定数を使用するために何が必要な場合は?この場合、まだ$offsetを定義する必要がありますか?

+24

これは分かりませんが、Rubyでは行頭にセミコロンを置く必要はありません。あなたは使用する必要があります。同じ行の複数のステートメントを区切る。 "a = 5; b = 10" – mikej

答えて

53

あなたが実現する必要があることの1つは、Rubyのすべてがオブジェクトです。それで、ModuleまたはClassの中にメソッドを定義しないと、RubyはObjectクラスに入れます。したがって、コードはObjectスコープのローカルになります。

オブジェクト指向プログラミングに関する一般的なアプローチは、クラス内のすべてのロジックをカプセル化している:

class Point 
    attr_accessor :x, :y 

    # If we don't specify coordinates, we start at 0. 
    def initialize(x = 0, y = 0) 
    # Notice that `@` indicates instance variables. 
    @x = x 
    @y = y 
    end 

    # Here we override the `+' operator. 
    def +(point) 
    Point.new(self.x + point.x, self.y + point.y) 
    end 

    # Here we draw the point. 
    def draw(offset = nil) 
    if offset.nil? 
     new_point = self 
    else 
     new_point = self + offset 
    end 
    new_point.draw_absolute 
    end 

    def draw_absolute 
    puts "x: #{self.x}, y: #{self.y}" 
    end 
end 

first_point = Point.new(100, 200) 
second_point = Point.new(3, 4) 

second_point.draw(first_point) 

ホープは、これはビットを明確。

+0

リファクタリングの場合+1。 'Object'スコープのローカルなトップレベルコードに関しては、' $ 'プレフィックスのない変数にも当てはまりますが、これとは対照的に、_methods_には_are_ global(' Object'クラスのprivateメンバーになります) )。 – mklement0

+0

私は私のケースでは、すべての 'Point'オブジェクトが一定のオフセットを基準にしている場合、' draw_absolute() 'がこのクラスを使用するように、オフセット(x、y)をクラス定数として持つことができますオフセットとしての定数 –

-2

私はあなたがオフセットを宣言したファイルのローカルだと思います。すべてのファイルをメソッドそのものとみなしてください。

多分、クラス全体に入れて、@@offset = Point.new(100, 200);でクラス変数をオフセットするのでしょうか?

+1

いいえ、ローカル変数はファイルに対してローカルではなく、宣言されている最も内側のブロックです。 –

9

グローバル変数がプレフィックス($)を必要とする理由の1つは、RubyではCとは異なり、変数を割り当てる前に宣言する必要がないため、あなたの描画メソッドの中にoffset = Point.new(100, 200)のようなステートメントがあれば、Rubyは既存の変数を参照しているのか、メソッド内に新しいローカル変数を作成しているのか分かりません。インスタンス変数の接頭辞は@と同じです。

+2

'$'はこれが新しい変数であるか既存の変数であるかをRubyに知らせていますか?既存の '$ foo'と思って' $ foo'に何かを割り当てても、 '$ foo'がまだ存在しないか、または誰かがそれを削除した場合、Rubyは' $ foo'を作成しますそれにもかかわらず、新しいグローバルとして、あなたが考えていた '$ foo'と同じではありません。 '$'は適切な宣言の欠如を修復しません。 – SasQ

+3

Rubyの変数sigils( '$'、 '@'、 '@@')は、より高いスコープの変数の不注意なシャドーイングを防ぐために必要であると言います。 しかし、Rubyの変数をシャドーするのは不可能です。変数は(sigilsなしで)常に定義されているスコープに対してローカルであるからです(これは最も内側のブロックですが、制限された例外はコードブロックです。範囲)。したがって、問題は_宣言の_欠点ではなく、_scope_の問題ではありません。ローカル変数とは別のスコープ内の変数から変数を参照する必要があります。 – mklement0

107

Rubyの変数スコープはsigilsによってある程度制御されます。 $で始まる変数はグローバル、@の変数はインスタンス変数、@@はクラス変数、大文字で始まる名前は定数です。他のすべての変数は地元の人々です。クラスまたはメソッドを開くと、これは新しいスコープであり、以前のスコープで使用可能なローカルは利用できません。

グローバル変数の作成を避けることをお勧めします。一般的に私がクリーナーと考え​​る同じ目的を達成する2つのテクニックがあります:

  1. モジュールで定数を作成します。この場合、オフセットが必要なすべてのクラスをモジュールFooに配置し、定数Offsetを作成すると、すべてのクラスがFoo::Offsetにアクセスできるようになります。

  2. 値にアクセスする方法を定義します。メソッドをグローバルに定義することもできますが、モジュールやクラスにカプセル化する方が良いと思います。このようにして、必要な場所でデータを利用できるようになります。必要に応じてデータを変更することもできますが、プログラムの構造とデータの所有権が明確になります。これは、OOの設計原則に沿ったものです。

関連する問題