模块

Nim支持用模块的概念把一个程序拆分成片段。每个模块在它自己的文件里。模块实现了 信息隐藏 和 编译隔离 。一个模块可以通过 import 语句访问另一个模块符号。 只有标记了星号(*)的顶级符号被导出:

  1. # Module A
  2. var
  3. x*, y: int
  4.  
  5. proc `*` *(a, b: seq[int]): seq[int] =
  6. # 分配新序列:
  7. newSeq(result, len(a))
  8. # 两个序列相乘:
  9. for i in 0..len(a)-1: result[i] = a[i] * b[i]
  10.  
  11. when isMainModule:
  12. # 测试序列乘 ``*`` :
  13. assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])

上面的模块导出 x*, 但没有 y

一个模块的顶级语句在程序开始时执行,比如这可以用来初始化复杂数据结构。

每个模块有特殊的魔法常量 isMainModule 在作为主文件编译时为真。 如上面所示,这对模块内的嵌入测试非常有用。

一个模块的符号 可以module.symbol 语法 限定 。如果一个符号有歧义,它 必须 被限定。一个符号有歧义如果定义在两个或多个不同的模块并且被第三个模块导入:

  1. # Module A
  2. var x*: string
  1. # Module B
  2. var x*: int
  1. # Module C
  2. import A, B
  3. write(stdout, x) # error: x 有歧义
  4. write(stdout, A.x) # okay: 用了限定
  5.  
  6. var x = 4
  7. write(stdout, x) # 没有歧义: 使用模块C的x

但这个规则不适用于过程或迭代器。重载规则适用于:

  1. # Module A
  2. proc x*(a: int): string = $a
  1. # Module B
  2. proc x*(a: string): string = $a
  1. # Module C
  2. import A, B
  3. write(stdout, x(3)) # no error: A.x is called
  4. write(stdout, x("")) # no error: B.x is called
  5.  
  6. proc x*(a: int): string = discard
  7. write(stdout, x(3)) # 歧义: 调用哪个 `x` ?