作用域

一个声明语句将程序中的实体和一个名字关联,比如一个函数或一个变量。声明语句的作用域是指源代 码中可以有效使用这个名字的范围。 不要将作用域和生命周期混为一谈。声明语句的作用域对应的是一个源代码的文本区域;它是一个编译 时的属性。一个变量的生命周期是指程序运行时变量存在的有效时间段,在此时间区域内它可以被程序 的其他部分引用;是一个运行时的概念。

语法块是由花括弧所包含的一系列语句,就像函数体或循环体花括弧对应的语法块那样。语法块内部声 明的名字是无法被外部语法块访问的。语法决定了内部声明的名字的作用域范围。我们可以这样理解, 语法块可以包含其他类似组批量声明等没有用花括弧包含的代码,我们称之为语法块。有一个语法块为 整个源代码,称为全局语法块;然后是每个包的包语法决;每个for、if和switch语句的语法决;每个 switch或select的分支也有独立的语法决;当然也包括显式书写的语法块(花括弧包含的语句)。

声明语句对应的词法域决定了作用域范围的大小。对于内置的类型、函数和常量,比如int、len和true 等是在全局作用域的,因此可以在整个程序中直接使用。任何在在函数外部(也就是包级语法域)声明 的名字可以在同一个包的任何源文件中访问的。对于导入的包,例如tempconv导入的fmt包,则是对应源 文件级的作用域,因此只能在当前的文件中访问导入的fmt包,当前包的其它源文件无法访问在当前源文 件导入的包

在包级别,声明的顺序并不会影响作用域范围,因此一个先声明的可以引用它自身或者是引用后面的一 个声明,这可以让我们定义一些相互嵌套或递归的类型或函数。但是如果一个变量或常量递归引用了自 身,则会产生编译错误。

  1. if f, err := os.Open(fname); err != nil { // compile error: unused: f
  2. return err
  3. }
  4. f.ReadByte() // compile error: undefined f
  5. f.Close() // compile error: undefined f

变量f的作用域只有在if语句内,因此后面的语句将无法引入它,这将导致编译错误。你可能会收到一个 局部变量f没有声明的错误提示,具体错误信息依赖编译器的实现。