Maison > développement back-end > Golang > Le type dynamique n'est pas effacé lors de la réaffectation d'une variable : est-ce un bug ?

Le type dynamique n'est pas effacé lors de la réaffectation d'une variable : est-ce un bug ?

PHPz
Libérer: 2024-02-13 16:00:11
avant
512 Les gens l'ont consulté

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

L'éditeur de PHP est là pour répondre à une question courante : "Les types dynamiques ne sont pas effacés lors de la réaffectation des variables - est-ce un bug ?" En PHP, le type dynamique des variables est l'une de ses fonctionnalités importantes de flexibilité. Lorsque nous réattribuons une valeur d'un type différent à une variable, PHP ajustera automatiquement le type de variable en fonction de la nouvelle valeur. Cependant, nous pouvons parfois oublier d'effacer les variables et obtenir des résultats inattendus. Alors, cette situation est-elle considérée comme une erreur ? Explorons-le ensemble.

Contenu de la question

Il existe une bizarrerie bien connue dans Go selon laquelle les interfaces contenant des valeurs nulles ne sont pas égales à zéro. En effet, sous le capot, une interface est une combinaison d'un type dynamique et d'une valeur, qui n'est nulle que si les deux sont nulles. Alors (*MyStruct)(nil) != nil(nil)(nil) == nil. Ce blog l'explique mieux.

J'ai trouvé quelque chose lié à ce comportement qui m'a surpris, ici : https://goplay.tools/snippet/VF8oWt9XvO8. Le code est également copié ci-dessous.

Il semble que si vous réaffectez une variable affectée d'un type dynamique, le type dynamique est mémorisé et conservé comme nouvelle valeur. Cela me semble inattendu, je pensais que la réaffectation de la variable devrait écraser tout l'état passé.

J'ai vérifié la spécification de la langue mais c'est un peu vague : 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>
Copier après la connexion

On ne sait pas si cela signifie uniquement la valeur ou la valeur plus la saisie dynamique.

Ce comportement est-il intentionnel dans le langage, ou s'agit-il d'un effet secondaire de la réutilisation de la mémoire par le runtime pour la réallocation des variables sans effacer tous les états ?

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)
}
Copier après la connexion

Solution

Votre partie « inattendue » est la suivante :

err = FuncThatReturnsCustomError()
Copier après la connexion

Où vous attendez que le résultat soit la nilerr 是接口类型(error)的变量,FuncThatReturnsCustomError() 的返回类型为 *CustomError。这不是一个接口类型,而是一个具体类型(指向 CustomError 的指针)。由于它返回一个非接口值,因此当分配给接口类型的变量时,必须将其包装到接口值中。这是将创建非 nil valeur de l'interface. Cela n'a rien à voir avec le fait de « se souvenir » ou de « préserver » des informations de type ancien.

Si vous utilisez une fonction avec un type de résultat d'interface comme :

func returnNilErr() error {
    return nil
}
Copier après la connexion

et testez-le :

err = returnNilErr()
fmt.Printf("result of returnNilErr() == nil: %v\n", err == nil)
Copier après la connexion

Ce que vous obtenez (essayez-le sur Go Playground) :

result of returnNilErr() == nil: true
Copier après la connexion

Parce que returnNilErr()已经有接口结果类型(error),所以它的返回值不需要打包成接口值,在赋值给err les variables peuvent être utilisées telles quelles. p>

Voir les doublons associés/possibles : Masquer les valeurs nulles pour comprendre pourquoi Go échoue ici

FAQ Go : Pourquoi ma valeur d'erreur nulle n'est-elle pas égale à zéro ? 一个>

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal