Heim >Backend-Entwicklung >Golang >Wie verwende ich „defer' in Go mit geänderten Variablen richtig?

Wie verwende ich „defer' in Go mit geänderten Variablen richtig?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-12-11 09:54:14412Durchsuche

How to Correctly Use `defer` in Go with Modified Variables?

Klärung der Verwendung von „Defer“

In Go können wir mit der „defer“-Anweisung die Ausführung einer Funktion planen, kurz bevor die umgebende Funktion zurückkehrt. Dies kann jedoch zu Verwirrung führen, wenn es um Variablen geht, die innerhalb der einschließenden Funktion geändert werden.

Ursprüngliche Ausgabe

Betrachten Sie die folgende Funktion:

func printNumbers() {
  var x int

  defer fmt.Println(x)

  for i := 0; i < 5; i++ {
    x++
  }
}

Gemäß der Go-Spezifikation: Wenn eine „Defer“-Anweisung ausgeführt wird, werden der Funktionswert und die Parameter ausgewertet und für die spätere Ausführung gespeichert. Das bedeutet, dass, wenn die Funktion schließlich aufgerufen wird, der Wert von x immer noch 0 sein wird, da er zum Zeitpunkt der Verzögerung ausgewertet wurde.

Lösung mit anonymer Funktion

Um dieses Problem zu beheben, haben wir kann eine anonyme Funktion innerhalb der „defer“-Anweisung verwenden:

defer func() { fmt.Println(x) }()

Hier ist x kein Parameter der anonymen Funktion, daher wird es nicht ausgewertet, wenn die „defer“-Anweisung wird ausgeführt. Stattdessen wird der Wert von x zum Zeitpunkt des Aufrufs der anonymen Funktion erfasst, um sicherzustellen, dass der aktuellste Wert gedruckt wird.

Alternative Lösungen

  1. Verwendung eines Zeigers:

    var x int
    
    defer func() { fmt.Println(&x) }()

    Dieser Ansatz verwendet einen Zeiger auf x als Parameter der verzögerten Funktion. Wenn die „defer“-Anweisung ausgeführt wird, wird nur der Zeiger ausgewertet, nicht der Wert von x. Wenn die verzögerte Funktion aufgerufen wird, greift sie über den Zeiger auf den aktuellen Wert von x zu.

  2. Verwenden eines benutzerdefinierten Typs:

    type MyInt int
    
    func (m *MyInt) String() string {
      return strconv.Itoa(int(*m))
    }
    
    var x MyInt
    
    defer fmt.Println(&x)

    Diese Lösung ähnelt dem Zeigeransatz, verwendet jedoch einen benutzerdefinierten Typ (MyInt), der die String()-Methode implementiert. Durch die Implementierung von String() können wir steuern, wie der Wert von ein Deskriptortyp in Go, was bedeutet, dass sein Wert eine Referenz auf ein zugrunde liegendes Array ist. Wenn wir einen Slice verschieben, wird nur die Referenz ausgewertet, nicht die tatsächlichen Array-Elemente. Infolgedessen werden alle Änderungen, die nach der Verschiebung an den Slice-Elementen vorgenommen werden, in der gedruckten Ausgabe widergespiegelt.

  3. Umschließen in einer Struktur:

    var x []int
    
    defer fmt.Println(x)

    Dieser Ansatz ähnelt der Verwendung eines Zeigers, aber wir packen den Wert in eine Struktur ein, um zu vermeiden, dass der Zeiger im Deferred dereferenziert werden muss Funktion.

Das obige ist der detaillierte Inhalt vonWie verwende ich „defer' in Go mit geänderten Variablen richtig?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn