模块
Nim支持通过模块概念将程序拆分为多个部分。 每个模块都需要在自己的文件中,并且有自己的 命名空间 。 模块启用 信息隐藏 and 分开编译 。 模块可以通过 import 语句访问另一个模块的符号。 递归模块依赖 是允许的,但有点微妙。 仅导出标有星号(*
)的顶级符号。 有效的模块名称只能是有效的Nim标识符(因此其文件名为 标识符.nim )。
编译模块的算法是:
- 像往常一样编译整个模块,递归地执行import语句
- 如果有一个只导入已解析的(即导出的)符号的环;如果出现未知标识符则中止
这可以通过一个例子来说明:
- # 模块A
- type
- T1* = int # 模块A导出类型 ``T1``
- import B # 编译器开始解析B
- proc main() =
- var i = p(3) # 因为B在这里被完全解析了
- main()
- # 模块 B
- import A # 这里没有解析A,仅导入已知的A符号。
- proc p*(x: A.T1): A.T1 =
- # 这是有效的,因为编译器已经将T1添加到A的接口符号表中
- result = x + 1
Import语句
在 import 语句之后,可以跟随模块名称列表或单个模块名称后跟 except 列表以防止导入某些符号:
- import strutils except `%`, toUpperAscii
- # 行不通:
- echo "$1" % "abc".toUpperAscii
没有检查 except 列表是否真的从模块中导出。 此功能允许针对不导出这些标识符的旧版本模块进行编译。
Include语句
include 语句与导入模块有着根本的不同:它只包含文件的内容。 include 语句对于将大模块拆分为多个文件很有用:
- include fileA, fileB, fileC
导入的模块名
可以通过 as 关键字引入模块别名:
- import strutils as su, sequtils as qu
- echo su.format("$1", "lalelu")
然后无法访问原始模块名称。 符号 path/to/module 或 "path/to/module" 可用于引用子目录中的模块:
- import lib/pure/os, "lib/pure/times"
请注意,模块名称仍然是 strutils 而不是 lib/pure/strutils 因此 无法 做:
- import lib/pure/strutils
- echo lib/pure/strutils.toUpperAscii("abc")
同样,以下内容没有意义,因为名称已经是 strutils :
- import lib/pure/strutils as strutils
从目录中集体导入
语法 import dir / [moduleA, moduleB] 可用于从同一目录导入多个模块。
路径名在语法上是Nim标识符或字符串文字。如果路径名不是有效的Nim标识符,则它必须是字符串文字:
- import "gfx/3d/somemodule" # 在引号中因为'3d'不是有效的Nim标识符
伪import/include目录
目录也可以是所谓的“伪目录”。当存在多个具有相同路径的模块时,它们可用于避免歧义。
有两个伪目录:
std: std 伪目录是Nim标准库的抽象位置。 例如,语法 import std / strutils 用于明确地引用标准库的 strutils 模块。
pkg: pkg 伪目录用于明确引用Nimble包。 但是,对于超出本文档范围的技术细节,其语义为:使用搜索路径查找模块名称但忽略标准库位置 。 换句话说,它与 std 相反。
From import语句
在 from 语句之后,一个模块名称后面跟着一个 import 来列出一个人喜欢使用的符号而没有明确的完全限定:
- from strutils import `%`
- echo "$1" % "abc"
- # 可能:完全限定:
- echo strutils.replace("abc", "a", "z")
如果想要导入模块但是想要对 module 中的每个符号进行完全限定访问,也可以使用 from module import nil 。
Export语句
export 语句可用于符号转发,因此客户端模块不需要导入模块的依赖项:
- # 模块B
- type MyObject* = object
- # 模块A
- import B
- export B.MyObject
- proc `$`*(x: MyObject): string = "my object"
- # 模块C
- import A
- # B.MyObject这里已经被隐式导入:
- var x: MyObject
- echo $x
当导出的符号是另一个模块时,将转发其所有定义。您可以使用 except 列表来排除某些符号。
请注意,导出时,只需指定模块名称:
- import foo/bar/baz
- export baz