ProgrammierungGo Entwickler

Wie funktioniert copy() in Go beim Kopieren von Slices? Was sind die Besonderheiten, Einschränkungen und unerwarteten Effekte im Zusammenhang mit der Längen- und Kapazitätsänderung von Slices? Was passiert bei Überlappungen von Slices und dem Versuch, sie mit Überschneidungen zu kopieren?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

Die Funktion copy(dst, src []T) int kopiert die Elemente von src nach dst.

  • Gibt die Anzahl der kopierten Elemente zurück: min(len(dst), len(src)).
  • Das Kopieren erfolgt indexbasiert: die Elemente src[i] werden in dst[i] kopiert.
  • Es werden die Inhalte (Werte) kopiert, nicht die Zeiger auf Objekte.

Besonderheiten und Einschränkungen:

  • Wenn sich die Slices überlappen (z. B. eines ist ein Teil des anderen), erfolgt das Kopieren so, als ob zuerst ein Fragment der ursprünglichen Werte genommen und dann kopiert wird (es gibt keine Garantie für Korrektheit bei Überlappungen).
  • Wenn dst eine kleinere Länge hat als src, werden nur so viele Daten kopiert, wie die Länge von dst zulässt.
  • Wenn dst eine größere Kapazität als Länge hat, erweitert copy das Slice nicht? — Nein, nur die len(dst) wird als Zieltiefe betrachtet. Zum Erweitern verwenden Sie vorher append.

Beispiel:

a := []int{1,2,3,4,5} b := make([]int, 3) copy(b, a) // b: [1 2 3]

Überlappung:

x := []int{1,2,3,4} copy(x[1:], x[:3]) // [1 1 2 3]

Trickfrage

Kann copy() verwendet werden, um die Länge eines Slices zu erhöhen? Was passiert, wenn ein Slice-Ziel mit größerer Kapazität, aber kleinerer Länge als erforderlich, an copy übergeben wird?

Antwort:

  • copy() ändert die Länge des Ziel-Slices nicht — es kopiert nur bis len(dst)
  • Wenn dst eine Kapazität hat, die größer ist als die Länge, erweitern Sie es zuerst mit dst = dst[:newLen], dann verwenden Sie copy()

Beispiel, oft nicht offensichtlich:

a := []int{1,2,3} b := make([]int, 0, 5) copy(b, a) // b bleibt leer, da len(b)==0 b = b[:len(a)] copy(b, a) // jetzt b: [1,2,3]

Beispiele für reale Fehler aufgrund von Unkenntnis der Feinheiten des Themas


Geschichte

Im Projekt wurden Daten von einem Slice in einen anderen kopiert, in der Annahme, dass copy die Länge von dst automatisch auf das Notwendige erweitert. Das geschah nicht, die Elemente wurden nicht kopiert, was dazu führte, dass die API mit Null-Werten antwortete. Der Fehler wurde erst nach dem Vergleich der Längen der Slices gefunden — das Problem war, dass dst eine große Kapazität hatte, aber die Länge gleich 0 war.


Geschichte

Ein Teil des Mikrodienstes arbeitete mit sich überlappenden Slices und erwartete fälschlicherweise, dass copy immer korrekt funktioniert. Dadurch wurden die ursprünglichen Daten beim Vorwärtskopieren zerstört, und es traten "unsichtbare" Bugs beim Arbeiten mit Puffer auf. Das Problem wurde durch die Verwendung eines temporären Puffers gelöst (copy(tmp, src), dann copy(dst, tmp)).


Geschichte

Ein Ingenieur optimierte ein Array, indem er copy verwendete, um Daten zwischen Slices zu sortieren. Er erwartete, dass copy die Länge von dst korrigiert. Es stellte sich heraus, dass dies nicht geschah und es zu Panik und Überläufen von signifikanten Daten kam — vergessen wurde, die Länge des Slices vor dem Kopieren korrekt zu ändern.