作用域规则

标识符从它的声明处开始生效,并持续到到其声明所在的那个块结束。标识符为已知状态的那段代码范围称为标识符的作用域。标识符的准确的作用域与其声明方式有关。

块作用域

对于在块(block)的声明部分里声明的变量,其作用域从其声明处开始,直到块的末尾结束。 如果一个块里包含另一个块,在这个块里又再次声明了这个标识符,那么,在这个内部的块里,第二个声明有效。 当离开这个内部的块时,第一个声明又一次有效。在同一个块里,同一个标识符不能被重复定义, 除非是为了过程或者迭代器重载之目的。

元组或对象作用域

在元组或者对象定义里的字段标识符在下列地方有效:

  • 直到元组/对象的定义结束
  • 所给的元组/对象类型的变量的字段指示器(designators)
  • 对象类型的所有派生类型内

模块作用域

模块里的所有标识符从声明开始直到模块结束一直有效。间接依赖的模块里的标识符在本模块里 不可用 。 每个模块都自动导入了 system “系统”模块。

如果一个模块从两个不同模块里导入了相同的标识符,那么每次使用它时都必须加上限定,除非它是一个重载的过程或者迭代器, 这时重载解析会进来解决多义性:

  1. # 模块 A
  2. var x* : string
  1. # 模块 B
  2. var x* : int
  1. # 模块 C
  2. import A, B
  3. write(stdout, x) # 错误:x 指代不明
  4. write(stdout, A.x) # 正确:加上限定后 x 的指代明确
  5. var x = 4
  6. write(stdout, x) # 没有多义性: 这是模块 C 自己的 x

模块可以共享它们的名称,但是,当尝试使用模块名称来限定标识符时,编译器将因标识符不明确而失败。 可以通过为模块设置别名来限定标识符。

  1. # Module A/C
  2. proc fb* = echo "fizz"
  1. # Module B/C
  2. proc fb* = echo "buzz"
  1. import A/C
  2. import B/C
  3. C.fb() # Error: ambiguous identifier: 'fb'
  1. import A/C as fizz
  2. import B/C
  3. fizz.fb() # Works