2 Stimmen

Fremdheit in Ruby

Ich habe eine einfache if-Anweisung, die sich sehr seltsam verhält. Wenn ich innerhalb der if-Anweisung einen Wert an einen attr_accessor zuweise, wird der Wert gelöscht. Hier ist ein prägnantes Beispiel, das das Problem zeigt.

class FName
  attr_accessor :name
  attr_accessor :file_ext

  def full_name
    puts "ursprünglicher file_ext Wert: #{file_ext}"
    if file_ext.nil?
      file_ext = ".default"
    end
    puts "neuer file_ext Wert: #{file_ext}"
    "#{name}#{file_ext}"
  end
end

f = FName.new
f.name = "foo"
f.file_ext = ".txt"
puts f.full_name

Dies gibt folgendes aus:

ursprünglicher file_ext Wert: .txt
neuer file_ext Wert: 
foo

Das ist überhaupt nicht das, was man erwarten würde. Hat jemand eine Idee, was hier passiert?

Beachten Sie, dass ich dieses Problem sowohl in Ruby 2.0.0-p247 als auch in Ruby 2.1.1_1 reproduzieren kann. Beachten Sie auch, dass wenn ich die Zeile file_ext = ".falsch" entferne, das Codebeispiel wie erwartet funktioniert, wenn file_ext nicht nil ist, aber natürlich habe ich dann keine Möglichkeit, einen Standardwert bereitzustellen, wenn file_ext nil ist.

Ich habe versucht, puts-Anweisungen in den if-Block zu setzen, und (wie erwartet) geben sie nichts aus. Wenn ich die Zeile f.file_ext = ".txt" entferne, erhalte ich die Ausgabe:

ursprünglicher file_ext Wert: 
neuer file_ext Wert: .default
foo.default

Zu guter Letzt: Ich hoffe, den Standardwert auf diese Weise nur träge bereitzustellen, da in meinem echten Code der Wert berechnet wird und ich die Berechnung vermeiden möchte, es sei denn, es ist notwendig.

Hoffentlich kann mir jemand da draußen sagen, warum das passiert!

3voto

Gene Punkte 44687

Dies ist eine Eigenheit von Ruby. Die Zeile

      file_ext = ".default"

muss geändert werden zu

      self.file_ext = ".default"

Ohne das self., wird eine lokale Variable file_ext stillschweigend erstellt anstelle des Accessor-Aufrufs, den Sie beabsichtigt haben.

Es wird erstellt, auch wenn der if-Block nicht ausgeführt wird aufgrund der Deklarationssyntax von Ruby-Variablen. Es erhält automatisch den Wert nil, der als leerer String gedruckt wird. Hier ein Auszug aus dem Ruby RDoc:

Die lokale Variable wird erstellt, wenn der Parser auf die Zuweisung stößt, nicht wenn die Zuweisung stattfindet:

     a = 0 if false # weist a nicht zu
     p local_variables # gibt [:a] aus
     p a # gibt nil aus

Ich fühle mit Ihnen, nachdem ich insgesamt ein paar Stunden meines Lebens durch diese "Funktion" der Ruby-Syntax verloren habe. Vieles an Ruby ist wirklich schön, aber dies ist schlechtes Sprachdesign.

1voto

Arie Xiao Punkte 13889
def full_name
  puts "Anfangswert von file_ext: #{file_ext}" # Zeile 2
  if file_ext.nil?
    self.file_ext = ".default"     # aktualisiere diese Zeile (Zeile 4)
  end
  puts "neuer Wert von file_ext: #{file_ext}"
  "#{name}#{file_ext}"
end

Die Zeile 4 wird tatsächlich nicht ausgeführt, jedoch wird der Ruby-Quellcode-Analysator file_ext = ".default" als Zuweisung einer lokalen Variablen behandeln und nach Ausführung der if-Anweisung eine lokale Variable erstellen. Da die Zuweisung jedoch nicht tatsächlich aufgerufen wurde, wird die lokale Variable keinen gespeicherten Wert haben.

In Zeile 2 sucht Ruby nach der Variablen file_ext im lokalen Bereich. Wenn dies fehlschlägt, versucht es, die an self gebundene Methode file_ext aufzurufen und ruft die Methode von attr_accessor ab.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X