2009-03-04 8 views
418

In Ruby haben einige Methoden ein Fragezeichen (?), die eine Frage wie include? stellen, die fragen, ob das fragliche Objekt enthalten ist, das gibt dann ein true/false zurück.Warum werden in Ruby-Methoden Ausrufezeichen verwendet?

Aber warum haben einige Methoden Ausrufezeichen (!), wo andere nicht?

Was bedeutet das?

+15

Synonym: Knall, Ausrufezeichen – prusswan

+15

Die akzeptierte Antwort sollte http://stackoverflow.com/a/612653/109618 geändert werden. Siehe http://www.wobblini.net/bang.txt und http://www.ruby-forum.com/topic/176830#773946 - "Das Knallzeichen bedeutet" die Knallversion ist mehr gefährlich als sein nicht Knallgegenstück; vorsichtig handhaben "" -Matz –

+2

Die Bang-Methode wäre eine großartige Design-Wahl, wenn ** nur ** und ** alle ** Bang-Methoden gefährlich wären. Leider sind sie es nicht, und so wird es zu einer frustrierenden Übung, sich zu merken, was veränderbar ist und was nicht. –

Antwort

498

Im allgemeinen Methode, die in ! Ende zeigen, dass die Methode das Objekt ändert es auf genannt wird. Ruby nennt diese als "gefährliche Methoden", weil sie den Zustand ändern, auf den sich jemand anders beziehen könnte. Hier ist ein einfaches Beispiel für Strings:

foo = "A STRING" # a string called foo 
foo.downcase!  # modifies foo itself 
puts foo   # prints modified foo 

erhalten Sie folgende Ausgabe:

a string 

In den Standardbibliotheken gibt es viele Orte, die Sie Paare von ähnlich benannten Methoden sehen werden, eine mit der ! und eins ohne. Diejenigen ohne werden "sichere Methoden" genannt, und sie geben eine Kopie des Originals mit Änderungen an die Kopie, mit dem callee unverändert. Hier ist das gleiche Beispiel ohne !:

foo = "A STRING" # a string called foo 
bar = foo.downcase # doesn't modify foo; returns a modified string 
puts foo   # prints unchanged foo 
puts bar   # prints newly created bar 

Diese Ausgänge:

A STRING 
a string 

Denken Sie daran, dies ist nur eine Konvention ist, aber eine Menge von Ruby-Klassen folgen. Außerdem können Sie verfolgen, was in Ihrem Code geändert wird.

+2

Es gibt auch Fälle wie Exit gegen Exit! und (in Rails) sparen statt sparen! –

+13

Seien Sie sehr vorsichtig - viele kleinere Bibliotheken folgen dieser Konvention nicht.Wenn seltsame Dinge passieren, ersetzen oft obj.whatever! mit obj = obj.whatever! behebt es. Sehr frustrierend. –

+73

bang wird auch für Methoden verwendet, die eine Exception auslösen, wenn die Methode ohne, z. B .: 'save' und' save! 'In' ActiveRecord' – ecoologic

23

! bedeutet in der Regel, dass die Methode auf das Objekt einwirkt, anstatt ein Ergebnis zurückzugeben. Aus dem Buch Programming Ruby:

Methoden, die "gefährlich" sind, oder ändern Sie den Empfänger, möglicherweise mit einem abschließenden "!" Benannt werden.

56

Diese Namenskonvention wurde von Scheme aufgehoben.

1.3.5 Namenskonventionen

Vereinbarungsgemäß werden die Namen der Verfahren , die immer einen Booleschen Wert zurück der Regel am Ende in ``? ''. Solche Prozeduren heißen Prädikate.

Vereinbarungsgemäß werden die Namen von Prozeduren dass speichern Werte in zuvor zugewiesen Stellen (siehe Abschnitt 3.4) in der Regel in beenden ``! ‚‘. Solche Prozeduren werden Mutationsverfahren genannt. Nach Konvention ist der Wert, der von einem Mutationsverfahren zurückgegeben wird, nicht angegeben.

+1

+1 zu dieser Antwort seit hat eine Dokumentation, die vernünftige Erklärungen für die geben! Verwendung. Wirklich gute Antwort Steven – DavidSilveira

+0

Dank @DavidSilveira! –

118

Das Ausrufezeichen bedeutet viele Dinge, und manchmal kann man nicht viel anderes als "das ist gefährlich, sei vorsichtig" sagen.

Wie andere gesagt haben, wird es in Standardmethoden oft verwendet, um eine Methode anzugeben, die bewirkt, dass ein Objekt sich selbst mutiert, aber nicht immer. Beachten Sie, dass viele Standardmethoden ihren Empfänger ändern und kein Ausrufezeichen haben (pop, shift, clear), und einige Methoden mit Ausrufezeichen ändern ihren Empfänger nicht (exit!). Siehe zum Beispiel this article.

Andere Bibliotheken können es anders verwenden. In Rails bedeutet ein Ausrufezeichen oft, dass die Methode bei einem Fehler eine Ausnahmebedingung auslöst, anstatt stillschweigend zu reagieren.

Es ist eine Namenskonvention, aber viele Leute verwenden es auf subtil verschiedene Arten. In Ihrem eigenen Code ist es eine gute Daumenregel, sie immer dann zu verwenden, wenn eine Methode etwas "Gefährliches" tut, besonders wenn zwei Methoden mit demselben Namen existieren und eine davon "gefährlicher" ist als die andere. "Gefährlich" kann jedoch fast alles bedeuten.

13

Von themomorohoax.com:

Ein Knall in der unten angegebenen Weise verwendet kann, um meine persönlichen Präferenz.

1) Eine aktive Record-Methode löst einen Fehler aus, wenn die Methode nicht ausführt, was sie sagt.

2) eine aktive Datensatz Methode speichert den Datensatz oder ein Verfahren, speichert ein Objekt (z.B. Streifen!)

3) Ein Verfahren, etwas „extra“ der Fall ist, wie Pfosten irgendwo, oder hat eine Aktion.

Der Punkt ist: nur einen Knall verwenden, wenn Sie wirklich darüber nachgedacht haben, ob ist es notwendig, andere Entwickler den Ärger des Müssens Check zu speichern, warum Sie einen Knall verwenden.

Der Knall bietet anderen Entwicklern zwei Hinweise.

1) dass es nicht notwendig ist, das Objekt nach dem Aufruf der Methode zu speichern.

2) Wenn Sie die Methode aufrufen, wird die db geändert.

http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods

6

Einfache Erklärung:

foo = "BEST DAY EVER" #assign a string to variable foo. 

=> foo.downcase #call method downcase, this is without any exclamation. 

"best day ever" #returns the result in downcase, but no change in value of foo. 

=> foo #call the variable foo now. 

"BEST DAY EVER" #variable is unchanged. 

=> foo.downcase! #call destructive version. 

=> foo #call the variable foo now. 

"best day ever" #variable has been mutated in place. 

Aber wenn Sie jemals eine Methode downcase! in der Erklärung oben genannt, foo ändern würde dauerhaft downcase. downcase! würde kein neues String-Objekt zurückgeben, sondern die Zeichenfolge ersetzen, wodurch die foo vollständig geändert wird. Ich schlage vor, Sie verwenden downcase! nicht, es sei denn, es ist absolut notwendig.

13

Es ist am genauesten zu sagen, dass Methoden mit einem Bang! sind die mehr dangerous oder surprising Version. Es gibt viele Methoden, die ohne einen Knall wie .destroy mutieren und im Allgemeinen Methoden nur haben, wo eine sicherere Alternative in der Kernbibliothek existiert.

Zum Beispiel auf Array wir .compact und .compact! haben, beide Methoden mutieren das Array, aber .compact! gibt nil zurück, statt selbst wenn es keine Null ist in der Anordnung sind, die noch überraschender ist, als nur sich selbst zurückkehrt.

Die einzige Nicht-mutierende Methode, die ich mit einem Knall gefunden habe, ist Kernel ‚s .exit!, die so überraschender als .exit ist, weil Sie nicht SystemExit, während der Prozess Schließen fangen können.

Rails und ActiveRecord setzt diesen Trend fort, indem es Knall für mehr "überraschende" Effekte wie .create! verwendet, die Fehler beim Versagen erhöht.

+0

Ich mache eine Erwähnung für "Nil". – Nakilon

0

Endergebnis: ! Methoden ändern nur den Wert des Objekts, auf das sie aufgerufen werden, während eine Methode ohne ! einen manipulierten Wert zurückgibt, ohne das Objekt zu überschreiben, auf das die Methode angewendet wurde.

Verwenden Sie nur !, wenn Sie nicht den ursprünglichen Wert benötigen, der in der Variablen gespeichert ist, für die Sie die Methode aufgerufen haben.

ziehe ich es so etwas wie zu tun:

foo = "word" 
bar = foo.capitalize 
puts bar 

ODER

foo = "word" 
puts foo.capitalize 

Statt

foo = "word" 
foo.capitalize! 
puts foo 

Für den Fall, würde Ich mag wieder den ursprünglichen Wert zuzugreifen.

+0

Warum wurde das abgelehnt? – Charles

+1

Weil Ihre Antwort in keiner Weise hilfreich war. "Bottom line:! Methoden ändern nur den Wert des Objekts, an dem sie aufgerufen werden" ist einfach nicht wahr. – Darwin

+0

@ Darwin es _does_ den Wert des Objekts ändern. '!' mutiert das Objekt und gibt keine modifizierte Kopie zurück. – Charles

0
! 

Ich mag es, dies als eine explosive Veränderung zu betrachten, die alles zerstört, was davor gegangen ist. Bang oder Ausrufezeichen bedeutet, dass Sie eine dauerhafte gespeicherte Änderung in Ihrem Code vornehmen.

Wenn Sie zum Beispiel Rubys Methode für die globale Ersetzung gsub! verwenden, ist die von Ihnen vorgenommene Ersetzung permanent.

Eine andere Möglichkeit, die Sie sich vorstellen können, ist das Öffnen einer Textdatei und Suchen und Ersetzen, gefolgt von Speichern. ! macht das gleiche in Ihrem Code.

Eine weitere nützliche Erinnerung, wenn Sie aus der Bash-Welt kommen, ist sed -i hat diesen ähnlichen Effekt der dauerhafte gespeicherte Änderung zu machen.

1

"Destruktive Methoden" genannt Sie neigen dazu, die Originalkopie des Objekts, auf das Sie sich beziehen, zu ändern.

numbers=[1,0,10,5,8] 
numbers.collect{|n| puts n*2} # would multiply each number by two 
numbers #returns the same original copy 
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array 
numbers # returns [nil,nil,nil,nil,nil] 
Verwandte Themen