49 votes

Je ne comprends pas la portée locale de ruby

Dans cet exemple,

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bar

Ensuite foo(6) Résultats : 100 et foo(3) ne produit rien.

Cependant si je change la définition à

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bob

Je reçois une erreur "variable locale ou méthode non définie".

Ma question est donc pourquoi je n'obtiens pas cette erreur lorsque j'appelle foo(3) et que bar n'est jamais défini ?

55voto

Todd Points 1633

Il y a quelques choses qui se passent ici. Tout d'abord, les variables déclarées à l'intérieur du bloc if ont la même portée locale que les variables déclarées au niveau supérieur de la méthode, c'est pourquoi bar est disponible en dehors du if. Deuxièmement, vous obtenez cette erreur parce que bob est référencé sans prévenir. L'interpréteur Ruby ne l'a jamais vu et n'a jamais vu son initialisation auparavant. En revanche, il a déjà vu bar initialisé auparavant, à l'intérieur de l'instruction if. Donc, quand il arrive à bar, il sait qu'il existe. Combinez ces deux éléments et voilà votre réponse.

15voto

Jörg W Mittag Points 153275

Votre deuxième exemple est en fait une fausse piste : la raison pour laquelle vous obtenez une exception n'est pas parce que bob est non initialisé, mais parce qu'il est ambigu. Il est impossible de dire s'il s'agit d'une variable ou d'une méthode.

Votre premier exemple fonctionne, car les variables locales non initialisées (ainsi que les variables globales et les variables d'instance) évaluent à nil. Par conséquent, puts bar est tout à fait correct : dans un cas, bar est initialisé à 100 et cela évalue à 100, dans l'autre cas, il n'est pas initialisé et donc évalue à nil. puts appelle to_s sur son argument, qui est défini pour nil (il retourne simplement la chaîne vide), donc tout va bien.

Voir aussi En Ruby, pourquoi après le démarrage de irb, foo.nil? donne une erreur indéfinie, et @foo.nil? renvoie "true", et @@wah.nil? donne à nouveau une erreur ?

4voto

Matt Briggs Points 20291

Donc ne prenez pas cela comme une vérité absolue (puisque c'est plus basé sur l'observation que sur la compréhension), mais il semble que l'interpréteur Ruby signalera tout mot (sans sigle devant) à gauche d'un signe égal comme local. Votre exemple est étrange, c'est encore plus bizarre

def foo
  bar = bar
  puts bar // nil, qui est coercé en ""

Je ne comprends pas pourquoi ou comment cela fonctionne, mais voilà.

2voto

Andrew Grimm Points 22996

foo(3) ne produit rien. Il affiche un saut de ligne.

Utiliser inspect vous donnerait plus d'indices :

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bar.inspect
end

foo(3)

imprimerait

nil

bar est une variable à part entière, qui se trouve simplement avoir une valeur de nil.

0voto

Theo Points 60103

Je ne suis pas sûr de ce que vous demandez. Exécuter foo(3) avec la deuxième définition donnera toujours une erreur, car bob n'est jamais défini. L'argument de la méthode ne change pas cela.

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