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