2014-10-30 2 views
6

Ich schreibe eine Go-Funktion, die Pythons itertools.permutations() imitiert, aber alle Permutationen auf einmal zurückgibt, anstatt einzeln zu liefern.Golang - Unerwartetes Multi-Zuweisungsverhalten

Ich sehe ein unerwartetes Verhalten, wenn sie in den folgenden Codezeilen 2 Variablen gleichzeitig Aktualisierung:

setcopy := append([]int(nil), sorted...) 
for i := 0; i < r; i++ { 
    c := counters[r-1-i] 
    current[i], setcopy = setcopy[c], append(setcopy[:c], setcopy[c+1:]...) 
} 

ich korrekte Ergebnisse erhalten, wenn das obige Update Entkopplung:

current[i] = setcopy[c] 
setcopy = append(setcopy[:c], setcopy[c+1:]...) 

I wurde hauptsächlich von den Pop und Delete Beispielen aus dem SliceTricks Wiki-Artikel inspiriert. Gibt es einen signifikanten Unterschied zwischen dem und dem, was ich versuche?

Wenn Sie den vollständigen Code (einschließlich eines Beispiels der fehlerhaften Ausgabe und einige Druckanweisungen für das Debuggen) auschecken möchten, können Sie this Gist auschecken.

Antwort

7

The Go Programming Language Specification

Assignments

Die Zuordnung erfolgt in zwei Phasen. Zuerst werden die Operanden des Index Ausdrücke und Zeigerverdrängungen (einschließlich des impliziten Zeigers Verweise in Selektoren) auf der linken Seite und die Ausdrücke auf dem Recht in der üblichen Reihenfolge ausgewertet. Zweitens werden die Zuweisungen in der Reihenfolge von links nach rechts ausgeführt.

Operands

Operanden bezeichnen die elementaren Werte in einem Ausdruck. Ein Operand darf ein Literal sein, ein (möglicherweise qualifizierter) nicht leerer Bezeichner, der eine Konstante, Variable oder Funktion, einen Methodenausdruck, der eine -Funktion ergibt, oder einen in Klammern gesetzten Ausdruck bezeichnet.

Order of evaluation

Bei der Auswertung der Operanden eines Ausdrucks, Zuweisung oder Anweisung zurück, alle Funktionsaufrufe, Methodenaufrufe und die Kommunikation Operationen in lexikalischer von links nach rechts ausgewertet werden.

beispielsweise in der (funktions local) Zuordnung

y[f()], ok = g(h(), i()+x[j()], <-c), k() 

die Funktionsaufrufe und Kommunikation geschieht in der Reihenfolge f(), h(), i(), j(), < - c, g() und k(). Die Reihenfolge dieser Ereignisse gegenüber der Auswertung und Indexierung von x und der Auswertung von y ist jedoch nicht angegeben.

Appending to and copying slices

Wenn die Kapazität der s nicht groß genug ist, um die zusätzlichen Werte passen, weist Anfügen einen neuen, ausreichend großen Array, das darunter liegenden sowohl die bestehenden Slice-Elemente und die zusätzlichen Werte paßt. Andernfalls verwendet append das zugrunde liegende Array erneut.

Wird ein neues zugrunde liegendes Array zugewiesen?

Die Zuweisungsanweisung

current[i], setcopy = setcopy[c], append(setcopy[:c], setcopy[c+1:]...) 

erscheint

a := append(setcopy[:c], setcopy[c+1:]...) 
x := setcopy[c] 
y := a 
current[i], setcopy = x, y 

aber die Reihenfolge der Funktionsaufruf Ereignisse im Vergleich zur Bewertung der anderen Operanden wird nicht angegeben (Order of evaluation) äquivalent.

+0

Ich glaube nicht, da das 'append', das in der Zuweisung verwendet wird, tatsächlich die Größe des Slice reduziert/ein Element löscht (und daher wäre ein neues darunter liegendes Array nicht notwendig). – Redy

+1

Kann nicht erklären, warum, aber die Ausgabe ist die gleiche, als wenn der 'append' zuerst ausgeführt wird: http://play.golang.org/p/ZQ-4cMyNTJ – twotwotwo

+0

Es sieht aus, als ob Sie links-zu-versprochen werden richtige evalordnung - wenn niemand hier einen guten grund findet, würde ich mit diesem golang-nuts schlagen, scheint wirklich komisch. – twotwotwo