[Go]程序结构-作用域

引言:该系列笔记,是本人自学Go过程中整理的笔记,供大家参考。

词法域和词法块的定义

作用域和生命周期是两个概念

  1. 作用域:声明语句的作用域对应的是一个源代码的文本区域;它是一个编译时的属性
  2. 生命周期:一个变量的生命周期是指程序运行时变量存在的有效时间段,在此时间段之内可以被程序的其他部分引用;是一个运行时的概念

句法块是由花括弧所包含的一系列语句,比如由函数体或循环体包裹的内容一样。句法块内部声明的名字无法被外部访问。

词法块是指哪些没有在代码中显式地使用花括号包裹的声明;整个源代码文件就是一个词法块,为全局词法块;对于每个包、每个for、if和Switch语句也都有对应的词法块;哪些显式书写的词法块也算(就是被花括号包裹的),词法块中声明的变量不会被覆盖。

变量的优先级

优先级第一: 内置的类型、函数和常量优先级最高

优先级第二: 对于导入包中的包级名字(首字母大写),可以在当前导入包的源文件中随意使用。包中任意源文件声明的包级名字可以在包内随意访问(不要求首字母大写)。

优先级第三: 源文件中在词法块内部声明的名字,只能在内部引用,外部无法直接引用。

变量的访问顺序

当编译器访问一个变量的时候,会对其定义进行查找,查找过程是从最内部的词法块开始向全局作用域查找。如果没有找到就会报编译错误。如果内部已经声明了一个变量,外部词法块重新声明了变量。那么内部变量会覆盖外部变量。

package main 

import "fmt" 

var testStr string = "wait,I try to be init again" 

func main() { 

  testStr := "I try to be init" 

  fmt.Println(testStr)    // 最后输出的结果是 I try to be init 

} 

词法域的作用范围

先看这段代码:

package main 

import( 

  "fmt" 

) 

func main() { 

  x := "hello" 

  for _, x := range x { 

    x := x + 'A' - 'a' 

    fmt.Printf("%c", x) // 最后输出的结果是HELLO 

  } 

} 

这里一共有三个不同的x变量,其中有两个是显式声明的,一个是隐式声明的。for循环体花括号内和main()函数花括号内显式声明了x变量,for循环体隐式的初始化了一个x变量。main函数嵌套for循环体,所以main函数初始化的x变量可以在for循环体中也可以访问。

再看这段代码:

package main 

import ( 

  "log" 

  "os" 

) 

var cwd string 

func main() { 

  cwd, err := os.Getwd() 

  if err != nil { 

    log.Fatalf("os.Getwd fail, %v", err) // compile error 

  } 

} 

这里会报编译错误,为什么? 因为遵循由内向外的原则,首先找到main函数内部通过隐式初始化了cwd,这时外部声明的cwd已经没有,被覆盖了。go强调初始化的变量是一定要用到的,没有用到就会编译不通过。

其实这个问题,有可能会被忽略;比如在main函数内部用下cwd变量就能避免编译报错的问题:log.Println("working directory is s%", cwd);但是外部声明的cwd就一直没有被用到,是个bug。

所以最好的解决方式,就是直接声明err变量,不要隐式声明最好。var err error就完了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值