• lesserror
    2021-11-05
    关于这一块儿的知识其实还挺绕的。 不同代码块中的重名变量与变量重声明中的变量区别到底在哪儿?为了方便描述,我就把不同代码块中的重名变量叫做“可重名变量”吧。注意,在同一个代码块中不允许出现重名的变量,这违背了 Go 语言的语法。关于这两者的表象和机理,我们已经讨论得足够充分了。你现在可以说出几条区别?请想一想,然后再看下面的列表。 1. 变量重声明中的变量一定是在某一个代码块内的。注意,这里的“某一个代码块内”并不包含它的任何子代码块,否则就变成了“多个代码块之间”。而可重名变量指的正是在多个代码块之间由相同的标识符代表的变量。 2. 变量重声明是对同一个变量的多次声明,这里的变量只有一个。而可重名变量中涉及的变量肯定是有多个的。 3. 不论对变量重声明多少次,其类型必须始终一致,具体遵从它第一次被声明时给定的类型。而可重名变量之间不存在类似的限制,它们的类型可以是任意的。 4. 如果可重名变量所在的代码块之间,存在直接或间接的嵌套关系,那么它们之间一定会存在“屏蔽”的现象。但是这种现象绝对不会在变量重声明的场景下出现。

    作者回复: 👍

    共 7 条评论
    11
  • Amosヾ
    2021-11-05
    可不可以通过变量尽量不重名来避免变量遮蔽呢?

    作者回复: 不重名肯定不会遮蔽。但是实际编码中,一些常用的功能变量,比如表示错误的err、表示下标的i,表示key和value的k、v等,如果要做不同命名,很容易在代码中出现大量的k1,v1,k2,v2等,阅读起来总是感觉缺少了一些优雅感。不知你是否有同感。

    共 4 条评论
    9
  • 扣剑书生
    2021-12-02
    func checkYear() error { err := errors.New("wrong year") // 短变量形式,屏蔽了外层的包级变量 a,代替 其接收值 // err代替上面 的 err接收值 // 接收放在 switch 作用域外 a, err := getYear() switch a { case 2020: fmt.Println("哦哦哦it is", a, err) case 2021: fmt.Println("it is", a) err = nil } fmt.Println("after check, it is", a) return err }

    作者回复: 👍

    共 5 条评论
    8
  • 文经
    2021-11-12
    约定号包级别的变量用长的名字,越是局部的变量用越短小的名字,应该能够解决一大部分变量zhe遮蔽的问题。

    作者回复: 也算是一个办法。前提是明确规则,且大家都遵守。这样才能在协作中,减少遮蔽问题的发生频度。

    
    7
  • 程旭阳
    2021-11-06
    go1.17.1 `type new int`会报错: cannot assign new to a (type int) in multiple assignment cannot use new value as type int in assignment 修改为 `type new = int` 之后不再报错 思考题解决方法: package main import ( "fmt" "errors" ) var a int = 2020 func checkYear() error { err := errors.New("wrong year") switch a, err = getYear(); a { case 2020: fmt.Println("it is", a, err) case 2021: fmt.Println("it is", a) err = nil } fmt.Println("after check, it is", a) return err } type year = int func getYear() (year, error) { var b int16 = 2021 return year(b), nil } func main() { err := checkYear() if err != nil { fmt.Println("call checkYear error:", err) return } fmt.Println("call checkYear ok") }
    展开

    作者回复: 正确✅

    共 3 条评论
    5
  • 子杨
    2022-12-13 来自辽宁
    「作者回复: 一旦“禁止用预定义标识符定义新类型或者变量的行为”,那么new这样的预定义标识符就和关键字没啥区别了。」 想请问老师,预定义标识符和关键字的区别是啥?

    作者回复: 预定义标识符可以被重新定义。 比如 var new int = 5 这时new就是一个变量。 但关键字不可以做标识符。 你不能用for作为变量名: var for int = 5 // error

    
    4
  • Rayjun
    2021-11-06
    修改两个地方,把 a 的类型改成 new,并 去掉 switch 那的一个引号 var a new = 2020 func checkYear() error { err := errors.New("wrong year") switch a, err = getYear(); a { case 2020: fmt.Println("it is", a, err) case 2021: fmt.Println("it is", a) err = nil } fmt.Println("after check, it is", a) return err } type new int func getYear() (new, error) { var b int16 = 2021 return new(b), nil } func main() { err := checkYear() if err != nil { fmt.Println("call checkYear error:", err) return } fmt.Println("call checkYear ok") }

    作者回复: 有一点提醒一下:既然我们知道了new是预定义的标识符,我们在日常编写代码中尽量要避免重新定义new.

    
    3
  • 🐎
    2022-08-21 来自北京
    感觉和js一样,变量就近使用

    作者回复: 其实这是一个编程通用原则,利于提升可读性

    
    2
  • 史努比
    2022-03-27
    Universe Block是不是翻译成“全局代码块”更贴切一些,“宇宙代码块”总觉得怪怪的。

    作者回复: 我倒是觉得“宇宙代码块”更形象生动罒ω罒。否则go官方也不会用universe block,而会用global block了。 另外代码块不要与作用域混淆。包代码块中声明的首字母大写的标识符实际是也是拥有全局作用域的,可以被任意其他代码所引用的。

    
    2
  • Rayjun
    2022-03-01
    老师,这里我还有一个问题,我发现如果是在同级的作用域中,声明两个一样的变量就会报错,但是在不同级的作用域中就不会,那么 go 语言为何不禁止同名变量的声明,这样不就可以解决变量遮蔽的问题么

    作者回复: 好问题!不过这是编程语言设计范畴的问题,我不是编程语言设计专家,不能从原理上给予解释。但从目前情况来看,似乎没有哪门编程语言禁止不同作用域的同名变量声明,显然这是一个语言设计与实现的惯例。

    
    2