Как вы используете глобальные переменные или постоянные значения в Ruby? - PullRequest
66 голосов
/ 25 июня 2009

У меня есть программа, которая выглядит следующим образом:

$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 ]

110 голосов
/ 26 июня 2009

Область видимости переменной в Ruby до некоторой степени контролируется символами. Переменные, начинающиеся с $, являются глобальными, переменные с @ являются переменными экземпляра, @@ означает переменные класса, а имена, начинающиеся с заглавной буквы, являются константами. Все остальные переменные являются локальными. Когда вы открываете класс или метод, это новая область, а локальные элементы, доступные в предыдущей области, недоступны.

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

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

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

53 голосов
/ 25 июня 2009

Одна вещь, которую вам нужно понять, это то, что в 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)

Надеюсь, это прояснит немного.

9 голосов
/ 25 июня 2009

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

0 голосов
/ 25 июня 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...