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.
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>
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) }
Votre partie « inattendue » est la suivante :
err = FuncThatReturnsCustomError()
Où vous attendez que le résultat soit la nil
。 err
是接口类型(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 }
et testez-le :
err = returnNilErr() fmt.Printf("result of returnNilErr() == nil: %v\n", err == nil)
Ce que vous obtenez (essayez-le sur Go Playground) :
result of returnNilErr() == nil: true
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!