68 votes

Comment utilisez-vous des variables globales ou des valeurs constantes dans Ruby?

J'ai un programme qui ressemble à ceci:

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

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

draw(Point.new(3, 4));

l'utilisation de l' $offset semble un peu bizarre.

En C, si je définir quelque chose en dehors de toute fonction, il est une variable globale automatiquement. Pourquoi Ruby-t-il $offset mais ne peut pas être offset et encore être global? Si c'est offset, alors c'est un local? Mais local où, parce qu'il se sent très bien mondiale.

Sont t-il de meilleures façons d'écrire le code ci-dessus? L'utilisation de l' $offset peut sembler un peu moche au premier abord.


Mise à jour: je peux mettre ce décalage à l'intérieur d'un class définition, mais que faire si deux ou plusieurs classes ont besoin d'utiliser cette constante? Dans ce cas, dois-je encore besoin de définir un $offset?

113voto

Chuck Points 138930

La portée des variables en Ruby, c'est contrôlée par des sceaux à un certain degré. Les Variables commençant par $ sont globales, variables avec @ sont variables d'instance, @@ moyen de variables de classe, et les noms commençant par une majuscule sont des constantes. Toutes les autres variables sont des locaux. Lorsque vous ouvrez une classe ou d'une méthode, c'est un nouveau champ d'application, et les locaux disponibles dans l'ancien périmètre ne sont pas disponibles.

En général, je préfère éviter de créer des variables globales. Il existe deux techniques généralement d'atteindre le même objectif que je considère plus propre:

  1. Créer une constante dans un module. Donc, dans ce cas, vous devez mettre toutes les classes qui ont besoin de l'offset dans le module Foo et de créer une constante Offset, alors toutes les classes pouvaient accéder Foo::Offset.

  2. Définir une méthode pour accéder à la valeur. Vous pouvez définir la méthode à l'échelle mondiale, mais encore une fois, je pense que c'est mieux de l'encapsuler dans un module ou d'une classe. De cette façon, les données sont disponibles là où vous en avez besoin et vous pouvez même modifier si vous avez besoin, mais la structure de votre programme et de la propriété des données sera plus clair. Ce n'est plus en ligne avec les principes de conception OO.

54voto

Igor Points 1963

Une chose que vous devez réaliser est qu'en Ruby tout est un objet. Dans ces conditions, si vous ne définissez pas vos méthodes dans Module ou Class , Ruby le mettra dans la classe Object . Ainsi, votre code sera local à la portée Object .

Une approche typique de la programmation orientée objet consiste à encapsuler toute la logique dans une classe:

 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 overload 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)
 

J'espère que cela clarifie un peu.

10voto

mikej Points 30224

L'une des raisons pour lesquelles la variable globale a besoin d'un préfixe (les $ ) est dû au fait qu'en Ruby, contrairement à C, vous n'avez pas à déclarer vos variables avant de les affecter, donc sans préfixe spécifique pour les globaux Étant donné une déclaration telle que offset = Point.new(100, 200) dans votre méthode de dessin, Ruby ne saurait pas si vous faites référence à la variable existante ou si vous créez une nouvelle variable locale dans votre méthode. Idem avec le préfixe @ pour les variables d'instance.

-3voto

Gábor Hargitai Points 380

Je pense que c'est local au fichier que vous avez déclaré compensé. Considérez chaque fichier comme une méthode en soi.

Peut-être mettre le tout dans une classe et ensuite compenser une variable de classe avec @@offset = Point.new(100, 200); ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X