Как вы используете глобальные переменные или постоянные значения в Ruby?
У меня есть программа, которая выглядит так:
$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
может показаться немного уродливым вначале.
Обновление: я могу поместить это смещение внутри определения class
, но что, если два или несколько классов должны использовать эту константу? В этом случае мне еще нужно определить $offset
?
Ответы
Ответ 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)
Надеюсь, это немного разъяснит.
Ответ 2
Переменная область в Ruby в некоторой степени контролируется сигилами. Переменные, начинающиеся с $
, являются глобальными, переменные с @
являются переменными экземпляра, @@
означает переменные класса, а имена, начинающиеся с заглавной буквы, являются константами. Все остальные переменные являются локальными. Когда вы открываете класс или метод, новая область и локали, доступные в предыдущей области, недоступны.
Обычно я предпочитаю избегать создания глобальных переменных. Есть два метода, которые обычно достигают той же цели, что я считаю более чистым:
-
Создайте константу в модуле. Поэтому в этом случае вы должны поместить все классы, которым требуется смещение в модуле Foo
, и создать константу Offset
, чтобы все классы могли получить доступ к Foo::Offset
.
-
Определите метод доступа к значению. Вы можете определить метод глобально, но опять же, я думаю, что лучше инкапсулировать его в модуле или классе. Таким образом, данные доступны там, где они вам нужны, и вы даже можете изменить их, если вам нужно, но структура вашей программы и права собственности на данные будут более четкими. Это больше соответствует принципам проектирования OO.
Ответ 3
Одна из причин, по которой глобальной переменной нужен префикс (так называемый "сигил"), заключается в том, что в Ruby, в отличие от C, вам не нужно объявлять переменные перед их присвоением. Сигил используется как способ явно указать область действия переменной.
Без специального префикса для глобалов, учитывая оператор pointNew = offset + point
внутри вашего метода draw
, тогда offset
ссылается на локальную переменную внутри метода (и в этом случае приводит к NameError
). То же самое для @
используется для ссылки на переменные экземпляра и @@
для переменных класса.
В других языках, которые используют явные объявления, такие как C
, Java
и т.д., Размещение объявления используется для управления областью действия.
Ответ 4
Я думаю, что это локально для файла, который вы заявили о смещении. Рассмотрите каждый файл как сам метод.
Возможно, поместите все это в класс, а затем сделайте смещение переменной класса с помощью @@offset = Point.new(100, 200);
?