次のようなプログラムがあります。
$offset = Point.new(100, 200);
def draw(point)
pointNew = $offset + point;
drawAbsolute(point)
end
draw(Point.new(3, 4));
$offset
の使用は少し奇妙に思えます。
Cでは、関数の外側に何かを定義すると、自動的にグローバル変数になります。なぜRubyである必要がありますが$offset
である必要がありますが、offset
であってグローバルであることはできませんか?offset
である場合、ローカル?しかし、それは非常にグローバルに感じられるので、どこでもローカルです。
上記のコードを書くより良い方法はありますか? $offset
の使用は、最初は少しugいように見えるかもしれません。
更新:このオフセットをclass
定義内に配置できますが、2つまたは複数のクラスでこの定数を使用する必要がある場合はどうなりますか?この場合、$offset
を定義する必要がありますか?
理解する必要があるのは、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)
これが少し明確になることを願っています。
Rubyの変数スコープはシギルによってある程度制御されます。$
で始まる変数はグローバル、@
の変数はインスタンス変数、@@
はクラスを意味します変数、および大文字で始まる名前は定数です。他のすべての変数はローカルです。クラスまたはメソッドを開くと、それは新しいスコープになり、以前のスコープで使用可能なローカルは使用できなくなります。
私は通常、グローバル変数の作成を避けることを好みます。クリーナーと考えるのと同じ目的を一般的に達成する2つの手法があります。
モジュールに定数を作成します。そのため、この場合、オフセットを必要とするすべてのクラスをモジュールFoo
に配置し、定数Offset
を作成して、すべてのクラスがFoo::Offset
にアクセスできるようにします。
値にアクセスするメソッドを定義します。メソッドはグローバルに定義できますが、繰り返しますが、モジュールまたはクラスにカプセル化する方が良いと思います。これにより、必要な場所でデータを利用でき、必要に応じてデータを変更することもできますが、プログラムの構造とデータの所有権はより明確になります。これは、OO設計原則に沿ったものです。
グローバル変数にプレフィックス(「シギル」と呼ばれる)が必要な理由の1つは、RubyではCとは異なり、変数を割り当てる前に変数を宣言する必要がないためです。シギルは、変数のスコープを明示する方法として使用されます。
グローバルの特定のプレフィックスがない場合、draw
メソッド内でステートメントpointNew = offset + point
を指定すると、offset
はメソッド内のローカル変数を参照します(この場合はNameError
になります) )。インスタンス変数の参照に使用される@
およびクラス変数の@@
についても同じです。
C
、Java
などの明示的な宣言を使用する他の言語では、スコープを制御するために宣言の配置が使用されます。