Ich habe kürzlich die Programmiersprache Ruby gelernt und alles in allem ist es eine gute Sprache. Aber ich war ziemlich überrascht zu sehen, dass es nicht so einfach war, wie ich erwartet hatte. Genauer gesagt schien mir die "Regel der geringsten Überraschung" nicht sehr respektiert zu sein (das ist natürlich ziemlich subjektiv). Beispielsweise:
x = true and false
puts x # displays true!
und die berühmten:
puts "zero is true!" if 0 # zero is true!
Was sind die anderen "Gotchas", vor denen Sie einen Ruby-Neuling warnen würden?
true and false
Rückkehr wahr?Antworten:
Wikipedia Ruby Fallstricke
Aus dem Artikel:
$
und@
geben keinen variablen Datentyp wie in Perl an, sondern fungieren als Bereichsauflösungsoperatoren.99.0
) oder eine explizite Konvertierung (99.to_f
) folgen . Es reicht nicht aus, einen Punkt (99.
) anzuhängen , da Zahlen für die Methodensyntax anfällig sind.0
,""
und[]
sind alle ausgewertettrue
. In C ist die Expression0 ? 1 : 0
ausgewertet0
(dh false). In Ruby ergibt es jedoch1
, wie alle Zahlen auswertentrue
; nurnil
undfalse
bewerten zufalse
. Eine Folge dieser Regel ist, dass Ruby-Methoden gemäß Konvention - beispielsweise Suchvorgänge mit regulären Ausdrücken - Zahlen, Zeichenfolgen, Listen oder andere nicht falsche Werte bei Erfolg, abernil
bei Misserfolg (z. B. Nichtübereinstimmung) zurückgeben. Diese Konvention wird auch in Smalltalk verwendet, wo nur die speziellen Objektetrue
undfalse
in einem booleschen Ausdruck verwendet werden können.char
für Zeichen bereitstellt ). Dies kann beim Schneiden von Zeichenfolgen zu Überraschungen führen:"abc"[0]
Erträge97
(eine Ganzzahl, die den ASCII-Code des ersten Zeichens in der Zeichenfolge darstellt); zu erhalten"a"
Verwendung"abc"[0,1]
(eine Teillänge 1) oder"abc"[0].chr
.Die Notation
statement until expression
führt im Gegensatz zu den entsprechenden Anweisungen anderer Sprachen (z. B.do { statement } while (not(expression));
in C / C ++ / ...) die Anweisung tatsächlich nie aus, wenn der Ausdruck bereits vorhanden isttrue
. Dies liegt daran, dassstatement until expression
tatsächlich syntaktischer Zucker vorbei ist, dessen Äquivalent in C / C ++
while (not(expression)) statement;
genau sostatement if expression
ist wieAllerdings die Notation
In Ruby wird die Anweisung tatsächlich einmal ausgeführt, auch wenn der Ausdruck bereits wahr ist.
Greeting << " world!" if Greeting == "Hello"
Erzeugt beispielsweise keinen Fehler oder keine Warnung. Dies ähneltfinal
Variablen in Java, aber Ruby verfügt im Gegensatz zu Java auch über die Funktionalität, ein Objekt "einzufrieren".Einige Funktionen, die sich insbesondere von anderen Sprachen unterscheiden:
Die üblichen Operatoren für bedingte Ausdrücke
and
undor
folgen nicht den normalen Vorrangregeln:and
Bindet nicht enger alsor
. Ruby hat auch Ausdruck Operatoren||
und&&
die Arbeit wie erwartet.def
insidedef
macht nicht das, was ein Python-Programmierer erwarten könnte:Dies gibt einen Fehler darüber, dass er
x
nicht definiert wurde. Sie müssen a verwendenProc
.Sprachmerkmale
()
, um eine mehrdeutige Bedeutung des Codes zu vermeiden. Die Nichtverwendung()
ist nach wie vor gängige Praxis und kann besonders hilfreich sein, wenn Ruby zusammen mit der aufgerufenen Methode als lesbare domänenspezifische Programmiersprache verwendet wirdmethod_missing()
.quelle
Neulinge werden Probleme mit Gleichstellungsmethoden haben :
Diese Beispiele sollten die ersten drei Methoden verdeutlichen:
Beachten Sie, dass == , Gl.? und gleich? sollte immer symmetrisch sein: wenn a == b dann b == a.
Beachten Sie auch, dass == und eql? Sind beide in der Klasse Object als Aliase gleich implementiert ? Also , wenn Sie eine neue Klasse erstellen und == und eql wollen? Um etwas anderes als eine einfache Identität zu bedeuten, müssen Sie beide überschreiben. Beispielsweise:
Die Methode === verhält sich anders. Erstens ist es nicht symmetrisch (a === b bedeutet nicht , dass b === a). Wie gesagt, Sie können a === b als "a entspricht b" lesen. Hier einige Beispiele:
Die case- Anweisung basiert auf der Methode === :
ist gleichbedeutend damit:
Wenn Sie eine neue Klasse , deren Instanzen repräsentieren eine Art von Behälter oder einen Bereich zu definieren (wenn es so etwas wie eine hat ? Umfassen oder ein ? Match - Methode), dann finden Sie könnte es sinnvoll , die außer Kraft zu setzen === Methode wie folgt:
quelle
Affen flicken . Ruby hat offene Klassen, so dass ihr Verhalten zur Laufzeit dynamisch geändert werden kann ...
Objekte reagieren möglicherweise auf undefinierte Methoden, wenn sie überschrieben wurden
method_missing
odersend
wurden. Dies nutzt Rubys nachrichtenbasierten Methodenaufruf aus. Das ActiveRecord- System von Rails nutzt dies mit großer Wirkung.quelle
Der folgende Code hat mich überrascht. Ich denke, es ist ein gefährlicher Fall: sowohl leicht zu treffen als auch schwer zu debuggen.
Dies druckt:
Aber wenn ich nur
comment =
etwas vor dem Block hinzufüge ...Dann bekomme ich:
Wenn eine Variable nur innerhalb eines Blocks definiert wird, wird sie am Ende des Blocks zerstört und
nil
bei jeder Iteration auf zurückgesetzt. Das erwarten Sie normalerweise. Wenn die Variable jedoch vor dem Block definiert ist , wird die äußere Variable innerhalb des Blocks verwendet, und ihr Wert bleibt daher zwischen den Iterationen bestehen.Eine Lösung wäre, dies stattdessen zu schreiben:
Ich denke, viele Leute (einschließlich mir) neigen dazu, "
a = b if c
" statt "a = (c ? b : nil)
" zu schreiben , weil es besser lesbar ist, aber offensichtlich Nebenwirkungen hat.quelle
a = (b if c)
, um den gewünschten Effekt ohne Ternär zu erzielen. Dies liegt daranb if c
, dass null bewertet wird, wennc
es sich um Falsey handelt.Beim Aufruf
super
ohne Argumente wird die überschriebene Methode tatsächlich mit denselben Argumenten wie die überschreibende Methode aufgerufen.Um tatsächlich
super
ohne Argumente anzurufen , müssen Sie sagensuper()
.quelle
B#hello
hatname = 42
vor demsuper
, dann heißt es „Hallo 42“.Blöcke und Methoden geben standardmäßig den Wert der letzten Zeile zurück. Das Hinzufügen von
puts
Anweisungen zum Debuggen am Ende kann unangenehme Nebenwirkungen verursachenquelle
Vererbung spielt keine Rolle bei der Bestimmung der Sichtbarkeit von Methoden in Ruby.
quelle
Ich hatte große Probleme, Klassenvariablen, Klassenattribute und Klassenmethoden zu verstehen. Dieser Code könnte einem Neuling helfen:
quelle
Eine Sache, die ich gelernt habe, war, den Operator || = vorsichtig zu verwenden. und seien Sie besonders vorsichtig, wenn Sie mit Booleschen Werten zu tun haben. Normalerweise habe ich a || = b als Catch All verwendet, um 'a' einen Standardwert zu geben, wenn alles andere fehlgeschlagen ist und 'a' gleich Null geblieben ist. aber wenn a falsch und b wahr ist, wird a wahr zugewiesen.
quelle
a = b if a.nil?
oder verwenden@a = b unless defined?(@a)
.Blöcke sind wirklich wichtig zu verstehen, sie werden überall verwendet.
Sie benötigen keine Klammern um Methodenparameter. Ob Sie sie verwenden oder nicht, liegt bei Ihnen. Einige sagen, Sie sollten sie immer verwenden .
Verwenden Sie Raise and Rescue für die Ausnahmebehandlung, nicht werfen und fangen.
Sie können verwenden
;
, müssen es aber nicht, es sei denn, Sie möchten mehrere Dinge in eine Zeile setzen.quelle
Ich hatte Probleme mit Mixins, die Instanzmethoden und Klassenmethoden enthalten . Dieser Code könnte einem Neuling helfen:
Zuerst dachte ich, ich könnte Module mit Instanzmethoden und Klassenmethoden haben, indem ich einfach Folgendes mache:
Leider wird die Methode number_of_displays niemals aufgenommen oder erweitert, da es sich um eine " Modulklassenmethode " handelt. Nur "Modulinstanzmethoden" können in eine Klasse aufgenommen werden (als Instanzmethoden) oder in eine Klasse erweitert werden (als Klassenmethoden). Aus diesem Grund müssen Sie die Instanzmethoden Ihres Mixins in ein Modul und die Klassenmethoden Ihres Mixins in ein anderes Modul einfügen (normalerweise fügen Sie die Klassenmethoden in ein Submodul "ClassMethods" ein). Dank der enthaltenen magischen Methode können Sie es einfach machen, sowohl Instanzmethoden als auch Klassenmethoden in nur einem einfachen Aufruf "include Displayable" einzuschließen (wie im obigen Beispiel gezeigt).
Dieses Mixin zählt jede Anzeige pro Klasse . Der Zähler ist ein Klassenattribut, daher hat jede Klasse ein eigenes (Ihr Programm schlägt wahrscheinlich fehl, wenn Sie eine neue Klasse aus der Person-Klasse ableiten, da der Zähler @number_of_displays für die abgeleitete Klasse niemals initialisiert wird). Möglicherweise möchten Sie @number_of_displays durch @@ number_of_displays ersetzen , um daraus einen globalen Zähler zu machen. In diesem Fall hat jede Klassenhierarchie einen eigenen Zähler. Wenn Sie einen globalen und eindeutigen Zähler möchten, sollten Sie ihn wahrscheinlich zu einem Modulattribut machen.
All dies war definitiv nicht intuitiv für mich, als ich mit Ruby anfing.
Ich kann immer noch nicht herausfinden, wie einige dieser Mixin-Methoden sauber privat oder geschützt werden können (nur die Methode display und number_of_displays sollten als öffentliche Methoden enthalten sein).
quelle
Achten Sie auf die Bereichsnotation.
(Zumindest, mehr Aufmerksamkeit schenken , als ich tat zunächst!)
Es gibt einen Unterschied zwischen
0..10
(zwei Punkten) und0...10
(drei Punkten).Ich mag Ruby sehr. Aber dieses Punkt-Punkt-gegen-Punkt-Punkt-Punkt-Ding nervt mich. Ich denke, dass solch ein subtiles "Feature" mit doppelter Syntax das ist:
sollte nicht in der Lage sein, verheerende Fehler in meinen Programmen zu verursachen.
quelle
for (i=0; i<max; i++)
undfor (i=0; i<=max; i++)
Ich denke, "
and
" und "or
" sind Anspielungen auf Perl, einen von Rubys offensichtlicheren "Eltern" (der prominenteste andere ist Smalltalk). Sie haben beide eine viel niedrigere Priorität (niedriger als die Zuordnung, von der das festgestellte Verhalten stammt) als&&
und||
welche Operatoren Sie verwenden sollten.Andere Dinge, die Sie beachten sollten, sind nicht sofort offensichtlich:
Sie rufen Methoden / Funktionen nicht wirklich auf, obwohl es irgendwie so aussieht. Stattdessen senden Sie wie in Smalltalk eine Nachricht an ein Objekt. Ist
method_missing
also wirklich eher somessage_not_understood
.ist äquivalent zu
Symbole sind sehr verbreitet. Das sind die Dinge, die anfangen
:
und die nicht sofort offensichtlich sind (nun, sie waren nicht für mich), aber je früher man sich mit ihnen auseinandersetzt, desto besser.Ruby ist ein großer Fan von "Ententypisierung" und folgt dem Prinzip "Wenn es wie eine Ente läuft und wie eine Ente quakt ...", das das informelle Ersetzen von Objekten durch eine gemeinsame Teilmenge von Methoden ohne explizite Vererbung oder Mixin-Beziehung ermöglicht.
quelle
Wenn Sie einen Setter (auch bekannt als Mutator) mit
attr_writer
oderattr_accessor
(oderdef foo=
) deklarieren , müssen Sie ihn nicht innerhalb der Klasse aufrufen. Da Variablen implizit deklariert werden, muss der Interpreter immerfoo = bar
eine neue Variable mit dem Namen foo deklarieren, anstatt die Methode aufzurufenself.foo=(bar)
.Dies gilt auch für Rails ActiveRecord-Objekte, bei denen Accessoren basierend auf Feldern in der Datenbank definiert werden. Da es sich nicht einmal um Instanzvariablen im @ -Stil handelt, können Sie diese Werte mit
self.value = 123
oder einzeln festlegenself['value'] = 123
.quelle
Den Unterschied zwischen Zeit- und Datumsklasse verstehen. Beide sind unterschiedlich und haben Probleme bei der Verwendung in Schienen verursacht. Die Zeitklasse steht manchmal in Konflikt mit anderen Zeitklassenbibliotheken, die in der Standard-Ruby / Rails-Bibliothek vorhanden sind. Ich persönlich habe viel Zeit gebraucht, um zu verstehen, was genau in meiner Rails-App vor sich ging. Später dachte ich mir, wann ich es tat
Time.new
Es bezog sich auf eine Bibliothek an einem Ort, den ich nicht einmal kannte.
Entschuldigung, wenn mir nicht klar ist, was ich genau sagen möchte. Wenn andere mit ähnlichen Problemen konfrontiert waren, erklären Sie dies bitte erneut.
quelle
Eines, das mich in der Vergangenheit aufgefallen ist, ist, dass die
\n
Escape-Sequenz newline character ( ) unter anderem nicht durch Zeichenfolgen in einfachen Anführungszeichen unterstützt wird. Der Backslash selbst wird ausgeblendet. Sie müssen doppelte Anführungszeichen verwenden, damit die Escape-Funktion wie erwartet funktioniert.quelle
0 und '' sind wahr, wie Sie betont haben.
Sie können eine Methode und ein Modul / eine Klasse mit demselben Namen haben (was sinnvoll ist, da die Methode tatsächlich zu Object hinzugefügt wird und somit einen eigenen Namespace hat).
Es gibt keine Mehrfachvererbung, aber häufig werden "Mixin-Module" verwendet, um mehreren Klassen gemeinsame Methoden hinzuzufügen.
quelle
false
undnil
sind die falschen. Alle anderen sind wahre Werte.Methoden können neu definiert werden und zu einem Geisteskratzer werden, bis Sie die Ursache entdecken. ( Zugegeben, dieser Fehler ist wahrscheinlich etwas "schwerer" zu erkennen, wenn die Aktion eines Ruby on Rails-Controllers versehentlich neu definiert wird! )
Lauf:
Aber rufen Sie es mit aktivierten Warnungen auf und Sie können den Grund sehen:
quelle
Ich denke, es ist immer gut, .length für Dinge zu verwenden ... da die Größe von fast allem unterstützt wird und Ruby dynamische Typen hat, können Sie wirklich seltsame Ergebnisse erzielen, wenn Sie .size aufrufen, wenn Sie den falschen Typ haben ... Ich würde es viel lieber bekommen a NoMethodError: undefinierte Methode `length ', daher rufe ich im Allgemeinen nie die Größe von Objekten in Ruby auf.
hat mich mehr als einmal gebissen.
Denken Sie auch daran, dass Objekte IDs haben. Daher versuche ich, keine Variablen mit dem Namen id oder object_id zu verwenden, um Verwirrung zu vermeiden. Wenn ich eine ID für ein Benutzerobjekt benötige, ist es am besten, sie so etwas wie user_id zu nennen.
Nur meine zwei Cent
quelle
Ich bin neu in Ruby und habe in meiner ersten Runde ein Problem mit dem Ändern von Floats / Strings in eine Ganzzahl festgestellt. Ich habe mit den Floats angefangen und alles als f.to_int codiert . Aber als ich fortfuhr und die gleiche Methode für Strings verwendete, wurde mir beim Ausführen des Programms eine Kurve geworfen.
Anscheinend hat ein String keine to_int- Methode, Floats und Ints jedoch.
Willkürliche Klammern warfen mich auch zuerst. Ich habe einen Code mit und einen ohne gesehen. Es dauerte eine Weile, bis mir klar wurde, dass beide Stile akzeptiert werden.
quelle
Im Zusammenhang mit der Antwort von monkut deuten Rubys
to_foo
Methoden darauf hin, wie streng eine Konvertierung sein wird.Kurze wie
to_i
,to_s
sagen Sie, dass es faul sein soll, und konvertieren Sie sie in den Zieltyp, auch wenn sie in diesem Format nicht genau dargestellt werden können. Beispielsweise:Die längeren expliziten Funktionen wie
to_int
,to_s
bedeutet , dass das Objekt nativ als diese Art von Daten dargestellt werden. BeispielsweiseRational
repräsentiert die Klasse alle rationalen Zahlen, sodass sie durch Aufrufen direkt als Fixnum- (oder Bignum-) Ganzzahl dargestellt werden kannto_int
.Wenn Sie die längere Methode nicht aufrufen können, bedeutet dies, dass das Objekt in diesem Typ nicht nativ dargestellt werden kann.
Wenn Sie also beim Konvertieren mit den Methodennamen faul sind, ist Ruby mit der Konvertierung faul.
quelle
Von In Ruby, warum wird
foo = true unless defined?(foo)
die Aufgabe nicht gemacht?Weil
foo
definiert ist alsnil
wanndefined?(foo)
aufgerufen wird.quelle
Es ist nicht garantiert, dass die Iteration über Rubin-Hashes in einer bestimmten Reihenfolge erfolgt. (Es ist kein Fehler, es ist ein Feature)
Hash#sort
ist nützlich, wenn Sie eine bestimmte Bestellung benötigen.Verwandte Frage: Warum sind Rubys Array von 1000 Hashes-Schlüssel- und Wertepaaren immer in einer bestimmten Reihenfolge?
quelle
Dieser hat mich einmal wütend gemacht:
quelle
1/2
ausgewertet wird0
, was nicht gleich ist0.5
, unabhängig vom Typ. JedochRational(1, 2) == 0.5
und1.0 == 1
.funktioniert nicht Sie müssen den Bereich in Klammern setzen, wie z
Sie glauben also nicht, dass Sie anrufen
5.each
. Ich denke, dies ist ein Vorrang, genau wie diex = true and false
Gotcha.quelle