Go报错xx is shadowed during return

调试 Go 程序报错 xx is shadowed during return,方法在返回的时候不是预期的返回结果,错误的产生应当是在相同作用域中出现了同名的变量导致,根据实际业务场景进行修改

所属分类 Golang

相关标签 变量报错作用域

问题复现

调试 Go 程序报错 xx is shadowed during return,该错误一般是在编译的时候产生。

找到错误的位置,优先分析是不是存在相同的变量名所致。

复现代码如下:

func main() {
    no, err := makeErr()
    fmt.Println(no, err)
}

func makeErr() (no int, err error) {
    if err != nil {
        no, err := doSomeWork1()
        fmt.Println(no, err)
        return
    }
    return
}

func doSomeWork1() (int, error) {
    return 1, nil
}

报错提示如下:

# command-line-arguments
.main.go:16:3: no is shadowed during return
.main.go:16:3: err is shadowed during return

错误描述

关于错误的完整解释如下:

It's a new scope, so a naked return returns the outer err. So it's almost certainly not what you meant, hence the error.

这是一个全新的作用域,如果直接返回时会将外部变量一起返回。因此,返回的内容可能不是你预期希望的内容。

我们对上面复现的代码进行分析,报错位置代码为:

no, err := doSomeWork1()
fmt.Println(no, err)
// 这里的return报错了
return

因为在 if err != nil 作为分支条件时,在 if 内的内容是一个全新的作用域。

因此,编写代码是 no, err := doSomeWork1() 不会报错,反之如果没有产生新的作用域时,这句代码编译会提示报错 No new variables on left side of :=。

func makeErr() (no int, err error) {
    // No new variables on left side of :=
    no, err := doSomeWork1()
    fmt.Println(no, err)
    return
}

因为方法的返回定义中定了变量名,func makeErr() (no int, err error) ,因此方法中直接写 return 也不会报错。

对于新作用域的变量,不建议与外部变量同名,可以考虑定义特别的名字。

func makeErr() (no int, err error) {
    if err != nil {
        // 内部作用域,定义其他名字
        no1, err1 := doSomeWork1()
        fmt.Println(no1, err1)
        // 可以考虑赋值给外部变量(根据具体业务区考虑)
        no = no1
        err = err1
        // 进行外部赋值的时候,一遍多用于多分支场景,内部可以不return
        return
    }
    return
}

如果不想定义太多的变量名,可以为内部分支或作用域直接返回具体的信息,已达到预期的返回内容。

func makeErr() (no int, err error) {
    if err != nil {
        no, err := doSomeWork1()
        fmt.Println(no, err)
        // 内部作用域直接绑定返回
        return no, err
    }
    return
}

这个方案在编写方法前可以考虑采用,具体使用还是依照业务场景具体分析。

如果方法返回定义没有定义变量名时,所有的 return 必须具体到所有的返回变量。

func makeErr() (int, error) {
    no, err := doSomeWork1()
    fmt.Println(no, err)
    // 内部作用域直接绑定返回
    return no, err
    // 错误:Not enough arguments to return
    return
}

米虫

做一个有理想的米虫,伪全栈程序猿,乐观主义者,坚信一切都是最好的安排!

本站由个人原创、收集或整理,如涉及侵权请联系删除

本站内容支持转发,希望贵方携带转载信息和原文链接

本站具有时效性,不提供有效、可用和准确等相关保证

本站不提供免费技术支持,暂不推荐您使用案例商业化

发表观点

提示

昵称

邮箱

QQ

网址

当前还没有观点发布,欢迎您留下足迹!

同类其他

Golang

Go语言 & 与 * 取值赋值以及函数入参的区别

在 Go 中函数可以接受值传递和指针传递,使用时就涉及到 & 内存地址(指针)与 * 指针赋值的使用,它们的区别是什么?在实际业务使用中,值传递和指针传递的分别应对什么场景需要?针对使用时机进行分析。

GoLand设置gofmt和goimports代码格式化

GoLand 在保存代码时,可以自动调用 gofmt 和 goimports 实现自动格式化代码,在新版本中可以通过 File Watchers 插件来完成这些配置,配置位置位于File

GOPROXY依赖包代理设置

Go1.11版本开始支持包依赖管理工具,新增了GOPROXY环境变量,用于配置依赖包下载代理,通过代理配置可以实现翻墙下载一些所需的依赖包,可以说相当实用

GoLand中旧工程导入飘红处理思路

对于绝大多数新的 Go 项目而言,因为使用 go modules 管理包依赖从而无需要关注工程的目录位置,但是对于一些旧/历史工程在导入 GoLand 之后会出现全面飘红,这个时候就需要逐一排查问题

Go数据类型rune介绍和使用

Go 中比较常见的 int、string、bool、float 基本数据类型之外还有其他的数据类型可以应用在特殊场景,比如 rune 就是类似于 int32,因为其可表示的字符范围更大,实际工作中可以用来计算字符串的真实长度

Go中接口的设计与实现

Go语言中的接口采用的是隐式实现,不需要去申明实现,只需要直接实现接口所定义的全部方法即可,同时区分了直接实现与指针实现两种形态,在实际使用时需要注意和关注

选择个人头像

昵称

邮箱

QQ

网址

评论提示

  • 头像:系统为您提供了12个头像自由选择,初次打开随机为你选择一个
  • 邮箱:可选提交邮箱,该信息不会外泄,或将上线管理员回复邮件通知
  • 网址:可选提交网址,评论区该地址将以外链的形式展示在您的昵称上
  • 记忆:浏览器将记忆您已选择或填写过得信息,下次评论无需重复输入
  • 审核:提供一个和谐友善的评论环境,本站所有评论需要经过人工审核