2010-11-11 17 views
47

In diesem BeispielIch verstehe nicht, lokalen Bereich rubin

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

Dann foo (6) Ausgänge: 100 und foo (3) gibt nichts.

Allerdings, wenn ich die Definition

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

Ich erhalte eine „nicht definiert lokale Variable oder Methode“ Fehler.

Also meine Frage ist, warum ich diesen Fehler nicht bekomme, wenn ich foo (3) und bar nie gesetzt werde?

Antwort

53

Es gibt ein paar Dinge hier los. Erstens haben Variablen, die innerhalb des Blocks if deklariert sind, den gleichen lokalen Gültigkeitsbereich wie Variablen, die auf der obersten Ebene der Methode deklariert sind, weshalb bar außerhalb der if verfügbar ist. Zweitens erhalten Sie diesen Fehler, weil bob gerade aus heiterem Himmel referenziert wird. Der Ruby-Interpreter hat ihn noch nie gesehen und nie zuvor initialisiert. Es hat jedoch bar vor, innerhalb der if-Anweisung initialisiert. Also, wenn es zu sperren gilt, weiß es, dass es existiert. Kombiniere diese beiden und das ist deine Antwort.

+2

Danke, yep Ich habe verstanden, wo der Bob-Fehler einfach nicht sicher war, warum ich keinen Bar-Fehler bekommen habe. Weißt du, ob ich mich auf dieses Verhalten verlassen kann, ist es Teil der Spezifikation? Zum Beispiel, kann ich nach der if-Anweisung bar für nil prüfen oder sollte ich wirklich auch bar = nil vor der if-Anweisung deklarieren? – rebo

+1

Ja, das ist ein zuverlässiges Verhalten. Bar = Nil zu deklarieren wäre sicherlich expliziter. Aber ich weiß nicht, dass die meisten Rubyisten das tun würden. Wenn Sie Ihre Methoden klein halten, sollte es nicht schwer zu verstehen sein, oder wo die Bar herkommt. – Todd

0

Ich bin mir nicht sicher, was Sie fragen. Das Ausführen von foo(3) mit der zweiten Definition wird immer einen Fehler ergeben, da bob nie definiert ist. Das Argument der Methode ändert das nicht.

3

Also nimm das nicht als Evangelium (da es mehr auf Beobachtung als auf Verständnis basiert), aber es scheint, als ob der Rubin-Interpretierer jedes Wort (ohne ein Sigil davor) links von einem Gleichen markieren würde als ein lokaler unterzeichnen. Ihr Beispiel ist seltsam, das ist noch bizarre

def foo 
    bar = bar 
    puts bar // nil, which gets coerced into "" 
end 

Ich verstehe nicht, warum oder wie es funktioniert, aber da haben Sie es.

+1

+1! JavaScript funktioniert auf die gleiche Weise. Es verschiebt alle Deklarationen nach oben und lässt Zuweisungen dort, wo sie sind. Dies kann ein wenig verwirrend sein. – jwueller

+2

Alles auf der LHS einer Zuweisung wird auf Null initialisiert: '>> falls falsch; test = was auch immer; Ende ; Test # => Null. Auf diese Weise funktioniert auch so etwas wie 'x || = 5', denn es bedeutet' x = x || 5 ', die sein wird: x = nil || 5 'falls x nicht vorher definiert wurde. –

+0

@jwueller Ruby verschiebt jedoch nicht alle Zuordnungen nach oben. 'setzt b; b = b; 'ergibt ' 'NameError: undefinierte lokale Variable oder Methode' b 'für main: Object'' – Ajedi32

14

Ihr zweites Beispiel ist eigentlich ein Ablenkungsmanöver: der Grund, warum Sie eine Ausnahme erhalten, ist nicht, weil bob nicht initialisiert ist, weil es mehrdeutig ist. Es ist unmöglich zu sagen, ob es sich um eine Variable oder eine Methode handelt.

Ihr erstes Beispiel funktioniert, weil nicht initialisierte lokale Variablen (sowie globale Variablen und Instanzvariablen) ergeben. Daher ist puts bar vollkommen in Ordnung: in einem Fall wird bar auf 100 initialisiert und dies wird zu 100 ausgewertet, im anderen Fall ist es nicht initialisiert und wird daher zu nil ausgewertet. puts Aufrufe to_s auf sein Argument, das für nil definiert ist (es gibt einfach die leere Zeichenfolge), so ist alles in Ordnung und schön.

Siehe auch In Ruby, why after starting irb, foo.nil? says undefined error, and @foo.nil? gives “true”, and @@wah.nil? gives error again?

+0

Ich kenne Ruby nicht, aber wenn das stimmt, dann ist die angenommene Antwort von Todd vermutlich nicht korrekt. Er impliziert, dass das Problem mit Bob nicht darin besteht, dass es null ist, sondern dass es nicht initialisiert ist. Die anderen Antworten deuten darauf hin, dass Sie Recht haben. – mickeyf

+0

@ Jörg: Vielen Dank, jetzt hast du es mir klar gemacht. Ich frage mich, ob Matz zu beschäftigt ist, um sich so klar zu machen, wie Sie es jetzt erklärt haben. Gute Antwort! –

2

foo(3) nicht ausgegeben nichts tut. Es gibt eine neue Zeile aus.

inspect verwenden würden Sie eher ein Hinweis geben:

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

foo(3) 

druckt

nil 

bar ist ein vollwertiger Variable, die nur einen Wert von nil haben passiert.