Как вы используете глобальные переменные или постоянные значения в 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 64

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 в некоторой степени контролируется сигилами. Переменные, начинающиеся с $ глобальные переменные с @ переменные экземпляра, @@ означает, что переменные класса, и имена, начинающиеся с буквы являются константами. Все остальные переменные являются локальными. Когда вы открываете класс или метод, это новая область, а локальные объекты, доступные в предыдущей области, недоступны.

Я вообще предпочитаю избегать создания глобальных переменных. Существует два метода что в целом достичь той же цели, что я считаю чище:

  1. создать константу в модуле. Поэтому в этом случае вы бы поместили все классы, которые нуждаются в смещении в модуле Foo и создать константу Offset, так что тогда все классы могли получить доступ Foo::Offset.

  2. определите метод для доступа к значению. Вы можете определить метод глобально, но опять же, я думаю, что лучше инкапсулировать его в модуль или класс. Таким образом, данные доступна, когда вам это нужно и вы даже можете изменить его, если это необходимо, но структура вашей программы и данные будут яснее. Это больше соответствует принципам проектирования OO.

одна из причин, почему глобальная переменная нужна префикс (тег $) заключается в том, что в Ruby, в отличие от C, вам не нужно объявлять свои переменные перед их назначением, поэтому без определенного префикса для глобалов задается оператор типа offset = Point.new(100, 200) внутри вашего метода draw тогда Ruby не знал бы, ссылаетесь ли вы на существующую переменную или создаете новую локальную переменную внутри вашего метода. То же самое с @ префикс для переменных экземпляра.

Я думаю, что это локально для файла, который вы объявили смещение. Считайте каждый файл сам по себе методом.

может быть, поместить все это в класс, а затем сделать смещение переменной класса с @@offset = Point.new(100, 200);?