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

nop*_*ole 67 ruby global-variables

我有一个看起来像这样的程序:

$offset = Point.new(100, 200);

def draw(point)
  pointNew = $offset + point;
  drawAbsolute(point)
end

draw(Point.new(3, 4));
Run Code Online (Sandbox Code Playgroud)

使用$offset看起来有点怪异.

在C中,如果我在任何函数之外定义某些东西,它会自动成为一个全局变量.为什么在Ruby中它必须$offset但不可能offset并且仍然是全局的?如果是offset,那么它是本地的吗?但是本地到哪里,因为它感觉非常全球化.

是否有更好的方法来编写上面的代码?$offset起初使用可能看起来有点难看.


更新:我可以将此偏移量放在class定义中,但如果两个或多个类需要使用此常量呢?在这种情况下,我还需要定义一个$offset吗?

Chu*_*uck 111

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

我通常更愿意避免创建全局变量.有两种技术通常达到我认为更清洁的相同目的:

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

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


Igo*_*gor 53

你需要意识到的一件事是在Ruby中,一切都是一个对象.鉴于此,如果你没有在规定的方法ModuleClass,红宝石将会把它的内部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)
Run Code Online (Sandbox Code Playgroud)

希望这有点澄清.


mik*_*kej 10

其中一个原因全局变量需要一个前缀(的原因pointNew = offset + point)是因为在Ruby中,与C,你没有给予类似的声明中分配给他们,所以没有特定的前缀为全局变量之前声明变量draw的平局中然后Ruby不会知道你是在引用现有变量还是在方法中创建一个新的局部变量.与offset实例变量的前缀相同.

  • `$`如何帮助Ruby知道这是一个新变量还是现有变量?如果你给`$ foo`分配了一些东西,认为它是一些现有的`$ foo`,但它确实没有任何`$ foo`,或者有人已经删除它,那么Ruby会创建`$ foo尽管如此,尽管它与你所想到的"$ foo"不一样,但作为一个新的全球化.`$`不会修复缺少适当的声明. (2认同)