Heim  >  Artikel  >  Backend-Entwicklung  >  Dynamischer Typ wird bei Neuzuweisung der Variable nicht gelöscht – ist das ein Fehler?

Dynamischer Typ wird bei Neuzuweisung der Variable nicht gelöscht – ist das ein Fehler?

PHPz
PHPznach vorne
2024-02-13 16:00:11446Durchsuche

重新分配变量时动态类型未清除 - 这是一个错误吗?

Der PHP-Editor ist hier, um eine häufig gestellte Frage zu beantworten: „Dynamische Typen werden bei der Neuzuweisung von Variablen nicht gelöscht – ist das ein Fehler?“ In PHP ist der dynamische Typ von Variablen eines seiner wichtigsten Flexibilitätsmerkmale. Wenn wir einer Variablen einen anderen Werttyp zuweisen, passt PHP den Variablentyp automatisch entsprechend dem neuen Wert an. Manchmal vergessen wir jedoch möglicherweise, Variablen zu löschen und erhalten unerwartete Ergebnisse. Zählt diese Situation also als Fehler? Lassen Sie es uns gemeinsam erkunden.

Frageninhalt

Es gibt eine bekannte Eigenart in Go, dass Schnittstellen mit Nullwerten nicht gleich Null sind. Dies liegt daran, dass eine Schnittstelle unter der Haube eine Kombination aus einem dynamischen Typ und einem Wert ist, der nur dann Null ist, wenn beide Null sind. Also (*MyStruct)(nil) != nil(nil)(nil) == nil. Dieser Blog erklärt es besser.

Ich habe hier etwas im Zusammenhang mit diesem Verhalten gefunden, das mich überrascht hat: https://goplay.tools/snippet/VF8oWt9XvO8. Der Code wird auch unten kopiert.

Es scheint, dass, wenn Sie einer Variablen, der ein dynamischer Typ zugewiesen wurde, den dynamischen Typ neu zuweisen, der dynamische Typ gespeichert und als neuer Wert beibehalten wird. Das erscheint mir unerwartet. Ich dachte, die Neuzuweisung der Variablen sollte den gesamten vorherigen Status überschreiben.

Ich habe die Sprachspezifikation überprüft, aber sie ist etwas vage: https://go.dev/ref/spec#Assignability

<code>
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block ... Redeclaration does not introduce a new variable; it just assigns a new value to the original.
</code>

Es ist nicht klar, ob dies nur den Wert oder den Wert plus dynamische Typisierung bedeutet.

Ist dieses Verhalten in der Sprache beabsichtigt oder handelt es sich um einen Nebeneffekt der Laufzeit, die Speicher für die Neuzuweisung von Variablen wiederverwendet, ohne den gesamten Status zu löschen?

Code:

package main

import (
    "fmt"
)

type CustomError struct{}

func (e *CustomError) Error() string {
    return "err"
}

// ===================

func FuncThatReturnsCustomError() *CustomError {
    return nil
}

func FuncThatReturnsCustomErrorAsErrorInterface() error {
    // although the underlying returned value is nil, the return value from this func != nil
    // https://glucn.medium.com/golang-an-interface-holding-a-nil-value-is-not-nil-bb151f472cc7
    return FuncThatReturnsCustomError()
}

// ===================

func main() {
    // Assign a non-nil value to err (value is nil, dynamic type is not)
    err := FuncThatReturnsCustomErrorAsErrorInterface()
    fmt.Printf("err == nil: %v                                    false because although the value is nil, the dynamic type is not nil (expected)\n", err == nil)

    // Call func where return type is a pointer to a struct and and returns nil
    // It is nil, as expected, this call is just to provide a comparison with the call after
    newlyDeclaredErr := FuncThatReturnsCustomError()
    fmt.Printf("newlyDeclaredErr == nil: %v                        true because func returned nil (expected)\n", newlyDeclaredErr == nil)

    // Exactly the same call as above, but reusing the original err variable instead of declaring a new one
    // Back to not nil, unexpected
    err = FuncThatReturnsCustomError()
    fmt.Printf("original err reassigned == nil: %v                false presumably because err remembered its old dynamic type even after reassignment (unexpected)\n", err == nil)

    // Reassign err again, but explicitly to nil rather than by calling a function that returns nil. This time it's nil again
    err = nil
    fmt.Printf("original err after assignment to nil == nil: %v    true, expected but not consistent with the case above\n", err == nil)
}

Lösung

Dein „unerwarteter“ Teil ist dieser:

err = FuncThatReturnsCustomError()

Wobei Sie erwarten, dass das Ergebnis der nilerr 是接口类型(error)的变量,FuncThatReturnsCustomError() 的返回类型为 *CustomError。这不是一个接口类型,而是一个具体类型(指向 CustomError 的指针)。由于它返回一个非接口值,因此当分配给接口类型的变量时,必须将其包装到接口值中。这是将创建非 nil Schnittstellenwert ist. Dies hat nichts mit dem „Erinnern“ oder „Bewahren“ alter Typinformationen zu tun.

Wenn Sie eine Funktion mit einem Schnittstellenergebnistyp wie:

verwenden
func returnNilErr() error {
    return nil
}

und testen Sie es:

err = returnNilErr()
fmt.Printf("result of returnNilErr() == nil: %v\n", err == nil)

Was Sie bekommen (probieren Sie es auf Go Playground):

result of returnNilErr() == nil: true

Weil returnNilErr()已经有接口结果类型(error),所以它的返回值不需要打包成接口值,在赋值给err Variablen unverändert verwendet werden können. p>

Siehe verwandte/mögliche Duplikate: Nullwerte ausblenden, um zu verstehen, warum Go hier fehlschlägt

Go-FAQ: Warum ist mein Null-Fehlerwert nicht gleich Null? 一个>

Das obige ist der detaillierte Inhalt vonDynamischer Typ wird bei Neuzuweisung der Variable nicht gelöscht – ist das ein Fehler?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen