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


68

我有一个程序,看起来像:

$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吗?


25
来自C的您可能不知道这一点,但是您不需要在Ruby的行尾放置半冒号。您只需要使用;分隔同一行上的多个语句,例如“ a = 5; b = 10”
mikej

Answers:


53

您需要意识到的一件事是,在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)

希望这可以澄清一点。


+1用于重构。关于顶级代码在Object作用域内是本地的:对于没有$前缀的变量,这是正确的,但是相比之下,放置在其中的方法全局的(同时也成为Object类的私有成员)。
mklement0 2014年

所以我认为,如果所有Point对象都相对于某个常数偏移量,那么我可以将偏移量(x,y)作为类常数,因此draw_absolute()将使用该类常数作为偏移量
极性

112

Ruby中的变量作用域在一定程度上受到信号的控制。以变​​量开头的变量$是全局变量,以变量开头的变量@是实例变量,@@表示类变量,以大写字母开头的名称是常量。所有其他变量均为本地变量。当您打开类或方法时,这是一个新作用域,而先前作用域中可用的本地人不可用。

我通常更喜欢避免创建全局变量。通常有两种技术可以达到我认为更清洁的相同目的:

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

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


10

全局变量需要前缀(称为“ sigil”)的原因之一是因为在Ruby中,与C语言不同,在分配变量之前不必声明变量。记号用作明确显示变量范围的一种方式。

如果没有全局变量的特定前缀,则pointNew = offset + pointdraw方法内部给定的语句将offset引用方法内部的局部变量(NameError在这种情况下,结果为)。同样对于@用来指实例变量和@@类变量。

在使用显式声明如其它语言CJava申报等的放置用于控制的范围。


2
$帮助Ruby如何知道这是一个新变量还是一个现有变量?如果您$foo认为某件事已经存在$foo,但碰巧它$foo还不存在,或者有人将其删除,则Ruby仍会创建$foo一个新的全局变量,尽管它与$foo您想的不一样。$无法修复缺少适当声明的情况。
2013年

-3

我认为它对于您声明为offset的文件是本地的。将每个文件视为一个方法本身。

也许把整个东西放到一个类中,然后用@@offset = Point.new(100, 200);?使offset变成一个类变量?


3
不,局部变量不是文件本地的,而是声明它的最里面的块的本地。
Teemu Leisti
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.