登录
首页 >  Golang >  Go问答

动态类型未清除时重新分配变量 - 这是否会出错?

来源:stackoverflow

时间:2024-02-08 20:54:03 441浏览 收藏

编程并不是一个机械性的工作,而是需要有思考,有创新的工作,语法是固定的,但解决问题的思路则是依靠人的思维,这就需要我们坚持学习和更新自己的知识。今天golang学习网就整理分享《动态类型未清除时重新分配变量 - 这是否会出错?》,文章讲解的知识点主要包括,如果你对Golang方面的知识点感兴趣,就不要错过golang学习网,在这可以对大家的知识积累有所帮助,助力开发能力的提升。

问题内容

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

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

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

我检查了语言规范,但它有点含糊:https://go.dev/ref/spec#Assignability


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.

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

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

代码:

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?一个>

以上就是《动态类型未清除时重新分配变量 - 这是否会出错?》的详细内容,更多关于的资料请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>