你如何在Ruby中使用全局变量或常量值?

时间:2009-06-25 06:03:23

标签: ruby global-variables

我的程序看起来像:

$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 个答案:

答案 0 :(得分:110)

Ruby中的变量范围在某种程度上受到了sigils的控制。以$开头的变量是全局变量,@变量是实例变量,@@表示类变量,以大写字母开头的名称是常量。所有其他变量都是本地变量。当您打开一个类或方法时,这是一个新的范围,并且前一个范围中可用的本地可用不可用。

我通常更愿意避免创建全局变量。有两种技术通常可以实现我认为更清洁的相同目的:

  1. 在模块中创建常量。因此,在这种情况下,您将所有需要偏移的类放在模块Foo中并创建一个常量Offset,这样所有类都可以访问Foo::Offset

  2. 定义访问该值的方法。您可以全局定义方法,但我认为最好将其封装在模块或类中。这样,您可以在需要的地方获得数据,如果需要,您甚至可以更改数据,但程序的结构和数据的所有权将更加清晰。这更符合OO设计原则。

答案 1 :(得分:53)

你需要意识到的一件事是在Ruby中,一切都是一个对象。鉴于此,如果您未在ModuleClass中定义方法,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 :(得分:9)

全局变量需要前缀($)的原因之一是因为在Ruby中,与C不同,在分配变量之前不必声明变量,因此没有特定的前缀globals在draw方法中给出了offset = Point.new(100, 200)之类的语句,然后Ruby不知道你是在引用现有变量还是在方法中创建一个新的局部变量。与实例变量的@前缀相同。

答案 3 :(得分:-2)

我认为它是您声明偏移的文件的本地。将每个文件视为一种方法本身。

也许将整个事物放入一个类中,然后使用@@offset = Point.new(100, 200);

来偏移一个类变量