2016-07-09 7 views
0

Warum erzeugen die folgenden zwei Codefragmente nicht die gleiche Ausgabe? Der Unterschied zwischen push und |= ist ein schwieriger. Ich nehme an, dass |= eine Aufgabe sein könnte einen Unterschied machen? Obendrein wären die Konstanten später auch sicher vor Veränderungen, schätze ich nicht? Der Code kommt von Antworten auf this question. Sie können es in action here sehen.Ruby-Klassenkonstanten und Vererbungsmysterium

class LibraryItem 

    ATTRIBUTES = ['title', 'authors', 'location'] 

end 

class LibraryBook < LibraryItem 

    ATTRIBUTES.push('ISBN', 'pages'] 

end 

puts LibraryItem::ATTRIBUTES 
puts LibraryBook::ATTRIBUTES 

> ["title", "authors", "location", "ISBN", "pages"] 
> ["title", "authors", "location", "ISBN", "pages"] 

und

class Foo 

    ATTRIBUTES = ['title','authors','location'] 

end 

class Bar < Foo 

    ATTRIBUTES |= ['ISBN', 'pages'] 

end 

puts Foo::ATTRIBUTES 
puts Bar::ATTRIBUTES 

> ["title", "authors", "location"] 
> ["title", "authors", "location", "ISBN", "pages"] 
+0

Im ersten Beispiel bezieht sich "ATTRIBUTES" auf das ** selbe ** Array in beiden Fällen, und das Ändern an einer Stelle bedeutet, dass die anderen auch die Änderungen sehen. Im zweiten Fall erstellen Sie ein neues Array für "Bar", anstatt das gemeinsame zu ändern, was zu dem gewünschten Verhalten führt. –

+0

Also ist es die Zuordnung, die den Unterschied macht?Das heißt, wenn meine Klasse unterklassifiziert wird, kann jede Unterklasse eine 'Konstante' ändern? – nus

+0

Dieser Code wird nicht kompiliert. –

Antwort

3

Konstanten in Rubin sind ein bisschen irreführend. eine Konstante neu zuordnen erzeugt eine Warnung:

Foo=1 
Foo=2 
(irb):5: warning: already initialized constant Foo 

Aber nichts hindert Sie die aktuellen Werte mutiert selbst, die push tut. Wenn Sie dies verhindern wollen, dann können Sie das Array einfrieren, das heißt

class LibraryItem  
    ATTRIBUTES = ['title', 'authors', 'location'].freeze 
end 

Versuche, um das Array zu mutieren wird nun eine Ausnahme ausgelöst. Nur ist das Array allerdings eingefroren, so dass Sie so etwas wie

LibraryItem::ATTRIBUTES.first.upcase! 

tun könnte (vorausgesetzt, Sie nicht gefroren Stringliterale eingeschaltet bekommen haben) und diese Änderung erlaubt wird. Ich kenne keinen anderen Weg, als die Zeichenfolgen einzeln einzufrieren (oder fixierte Zeichenfolgenliterale für diese Datei einzuschalten, auf Ruby 2.3 und höher).

+0

Danke, das klärt die Dinge ein bisschen – nus

+0

Um jeden einzufrieren würde nicht so schwer sein - du würdest einfach tun = [...] .map (&: einfrieren!). einfrieren! ' –

+0

Äh, einfach 'einfrieren', nicht 'einfrieren!'. Es tut uns leid. –

3

Im ersten Beispiel beziehen ATTRIBUTES auf das gleiche Array und Sie es ändern. Daher

puts LibraryItem::ATTRIBUTES 
puts LibraryBook::ATTRIBUTES 

produzieren die gleichen Ergebnisse.

Während im zweiten Fall, tun Sie a |= b, die eine Kurzschrift für a = a | b ist. Dadurch wird ein neues Array namens ATTRIBUTES für Klasse Bar erstellt. Daher

puts Foo::ATTRIBUTES 
puts Bar::ATTRIBUTES 

produzieren anderes Ergebnis. In dieser Frage können Sie mehr über Ruby Assignment Operator lesen. Ruby |= assignment operator

EDIT

Ruby-Arrays implementiert eine kleine Sammlung von Set-Operation mit &, | Operatoren.

Einzelrohr, | führen Union-Vorgang, d. H. Fügt nur einzigartige Elemente.

a = [:foo, :bar, :baz] 
a |= [:baz, :buz] # => [:foo, :bar, :baz, :buz] 
+0

Ja, mein Schlechter. Ich muss nicht auf Zuweisungsoperatoren aufpäppeln, aber auf dem Konzept von _constants_ tue ich anscheinend ... – nus

Verwandte Themen