Nim语言的模块化编程
前言
Nim支持把一大段程序分成若干个模块
一个模块就是一个源代码文件
每个模块都拥有它自己的名称空间
模块化可以起到封装(信息隐藏)和分步编译的作用
一个模块可以通过import语句获得另一个模块的符号
nim语言允许模块间的循环引用,
只有用星号(*)标记的顶级符号才会被导出给其他模块。
模块名和文件名相同,模块名的命名方式和nim编程语言的标识符命名方式相同
编译器编译模块的规则如下:
-
按照import的导入顺序,编译模块
-
如果存在循环引用,那么就只导入顶级符号(已解析的符号),如果编译器发现未知的标识符,那么就停止编译
请看下面的例子:
模块A的代码:
# Module A type T1* = int # Module A exports the type ``T1`` import B # the compiler starts parsing B proc main() = var i = p(3) # works because B has been parsed completely here main()
模块B的代码:
# Module B import A # A is not parsed here! Only the already known symbols # of A are imported. proc p*(x: A.T1): A.T1 = # this works because the compiler has already # added T1 to A's interface symbol table result = x + 1
看起来是不是很厉害呢?!
import语句
可以通过import导入一个或多个模块
(导入多个模块的话,只要在import后面跟上模块的名字即可,模块的名字用逗号隔开)
可以用except排除一个或多个模块中的符号
请看下面的示例代码:
import strutils except `%`, toUpper # doesn't work then: echo "$1" % "abc".toUpper
注意:如果导入的模块中并没有导出排除的标识符的话,nim编译器是不会给出报警或异常的
include语句
include语句完全不同于import语句,
include语句会迫使编译器把一个文件的源码“包含”到另一个文件中。
需要把一个文件拆分成多个文件的时候include语句很有用
include fileA, fileB, fileC
import语句中的模块名
import语句中的模块名可以设置别名
import strutils as su, sequtils as qu echo su.format("$1", "lalelu")
如果你用了别名的话,那么原来的模块名称就不起作用了
如果一个模块在某个子目录中
可以使用如下三种办法来导入该模块
import lib.pure.strutils, lib/pure/os, "lib/pure/times"
注意:虽然模块在子目录中,但是模块名并不包含路径
下面的代码是错误的:
import lib.pure.strutils echo lib.pure.strutils
下面这种代码设置也没有任何意义
import lib.pure.strutils as strutils
from...import...语句
如果你只想导入某一个模块的指定符号,那么你就可以使用这种语句
来看下面的代码:
from strutils import `%` echo "$1" % "abc" # 但开发人员还是可以用完全限定符调用这个模块的其他方法: echo strutils.replace("abc", "a", "z")
如果你想迫使开发人员必须在主调模块中使用完全限定符来调用被调模块的符号
那么你可以使用,下面这种方法
rom strutils import nil
Export语句
下来看下面三个模块的代码
# module B type MyObject* = object
# module A import B export B.MyObject proc `$`*(x: MyObject): string = "my object"
# module C import A # B.MyObject has been imported implicitly here: var x: MyObject echo($x)
模块A把模块B中的符号导出出来了
这样模块C就不用再导入模块B了