首页 > 后端开发 > Golang > 重新分配变量时动态类型未清除 - 这是一个错误吗?

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

PHPz
发布: 2024-02-13 16:00:11
转载
506 人浏览过

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

php小编小新在这里为大家解答一个常见的问题:“重新分配变量时动态类型未清除 - 这是一个错误吗?”在PHP中,变量的动态类型是其灵活性的一个重要特点。当我们重新给一个变量赋予不同类型的值时,PHP会自动根据新的值来调整变量的类型。然而,有时候我们可能会因为忘记清除变量而导致意外的结果。那么,这种情况算不算是一个错误呢?让我们一起来探讨一下。

问题内容

Go 中有一个众所周知的怪癖,即持有 nil 值的接口不等于 nil。这是因为在底层,接口是动态类型和值的组合,只有当两者都为 nil 时,它才为 nil。所以 (*MyStruct)(nil) != nil(nil)(nil) == nil。本博客对此进行了更好的解释。

我发现了一些与此行为相关的东西,这让我感到惊讶,在这里:https://goplay.tools/snippet/VF8oWt9XvO8。代码也复制如下。

看来,如果您重新分配分配了动态类型的变量,动态类型就会被记住并保留为新值。这对我来说似乎是出乎意料的,我认为重新分配变量应该覆盖所有过去的状态。

我检查了语言规范,但它有点含糊: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>
登录后复制

不清楚这是否仅意味着值,或者值加上动态类型。

这种行为是语言中有意为之的,还是运行时重新使用内存进行变量重新分配而不清除所有状态的一些副作用?

代码:

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)
}
登录后复制

解决方法

你“意想不到”的部分是这样的:

err = FuncThatReturnsCustomError()
登录后复制

您期望结果为 nilerr 是接口类型(error)的变量,FuncThatReturnsCustomError() 的返回类型为 *CustomError。这不是一个接口类型,而是一个具体类型(指向 CustomError 的指针)。由于它返回一个非接口值,因此当分配给接口类型的变量时,必须将其包装到接口值中。这是将创建非 nil 接口值的位置。这与“记住”或“保留”旧类型信息无关。

如果您使用具有如下接口结果类型的函数:

func returnNilErr() error {
    return nil
}
登录后复制

并测试它:

err = returnNilErr()
fmt.Printf("result of returnNilErr() == nil: %v\n", err == nil)
登录后复制

您会得到(在 Go Playground 上尝试一下):

result of returnNilErr() == nil: true
登录后复制

因为returnNilErr()已经有接口结果类型(error),所以它的返回值不需要打包成接口值,在赋值给err变量时可以照原样使用。 p>

查看相关/可能的重复:隐藏 nil 值,理解为什么 Go 在这里失败

Go 常见问题解答:为什么我的 nil 错误值不等于 nil?一个>

以上是重新分配变量时动态类型未清除 - 这是一个错误吗?的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
来源:stackoverflow.com
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板