Julia 的模塊是一個(gè)獨(dú)立的全局變量工作區(qū)。它由句法限制在 module Name ... end
之間。在模塊內(nèi)部,你可以控制其他模塊的命名是否可見(jiàn)(通過(guò) import
),也可以指明本模塊的命名是否為 public(通過(guò) export
)。
下面的例子展示了模塊的主要特征。這個(gè)例子僅為演示:
module MyModule
using Lib
using BigLib: thing1, thing2
import Base.show
importall OtherLib
export MyType, foo
type MyType
x
end
bar(x) = 2x
foo(a::MyType) = bar(a.x) + 1
show(io, a::MyType) = print(io, "MyType $(a.x)")
end
注意上述例子沒(méi)有縮進(jìn)模塊體的代碼,因?yàn)檎w縮進(jìn)沒(méi)有必要。
這個(gè)模塊定義了類(lèi)型 MyType
和兩個(gè)函數(shù)。foo
函數(shù)和 MyType
類(lèi)型被 export ,因此可以被 import 進(jìn)其他模塊使用。 bar
是 MyModule
的私有函數(shù)。
語(yǔ)句 using Lib
表明,Lib
模塊在需要時(shí)可用來(lái)解析命名。若一個(gè)全局變量在當(dāng)前模塊中沒(méi)有被定義,系統(tǒng)會(huì)在 Lib
export 的變量中搜索,并在找到后把它 import 進(jìn)來(lái)。在當(dāng)前模塊中凡是用到這個(gè)全局變量時(shí),都會(huì)去找 Lib
中變量的定義。
語(yǔ)句 using BigLib: thing1, thing2
是 using BigLib.thing1, BigLib.thing2
的縮寫(xiě)。
import
關(guān)鍵字支持與 using
所有相同的語(yǔ)法,但只能在一個(gè)時(shí)間上對(duì)一個(gè)名稱(chēng)進(jìn)行操作。它不像 using
那樣會(huì)添加用于搜索的模塊。import
與 using
的不同之處還在于導(dǎo)入這一功能時(shí)必須使用新的方法擴(kuò)展后的 import
。
在上述的 MyModule
中我們想向標(biāo)準(zhǔn)的 show
功能增加一個(gè)方法,所以我們必須寫(xiě)下 import Base.show
。
那些函數(shù)名只有通過(guò) using
功能才能看到的函數(shù)是不能被擴(kuò)展的。
importall
關(guān)鍵字顯式地導(dǎo)入導(dǎo)出指定模塊的所有名稱(chēng),其效果就像 import
單獨(dú)使用在它們的所有名稱(chēng)一樣。
一旦一個(gè)變量是通過(guò) using
或 import
使其可見(jiàn)的,一個(gè)模塊就可能無(wú)法創(chuàng)建它自己的同名的變量了。輸入變量必須是只讀的;對(duì)全局變量賦值總是會(huì)影響當(dāng)前模塊所擁有的變量,否則就會(huì)引發(fā)錯(cuò)誤。
我們要加載一個(gè)模塊時(shí),可以使用兩個(gè)主要關(guān)鍵字:using
和 import
。要了解他們的差異,可以考慮下面的例子:
module MyModule
export x, y
x() = "x"
y() = "y"
p() = "p"
end
在這個(gè)模塊中我們(使用關(guān)鍵字 export
)導(dǎo)出 x
和 y
功能,也包含了非導(dǎo)出函數(shù) p
。我們有幾個(gè)不同的方法來(lái)加載該模塊及其內(nèi)部功能到當(dāng)前工作區(qū),具體如下:
導(dǎo)入命令 | 導(dǎo)入變量 | 方法擴(kuò)展可用項(xiàng) |
---|---|---|
using MyModule | All export ed names (x and y), MyModule.x, MyModule.y and MyModule.p MyModule.x, MyModule.y and MyModule.p | |
using MyModule .x, MyModule.p | x and p | |
using MyModule: x, p | x and p | |
import MyModule | MyModule.x, MyModule.y and MyModule.p | MyModule.x, MyModule.y and MyModule.p |
import MyModule.x, MyModule.p | x and p | x and p |
import MyModule: x, p | x and p | x and p |
importall MyModule | All export ed names (x and y) | x and y |
大多數(shù)情況下,文件和文件名與模塊無(wú)關(guān);模塊只與模塊表達(dá)式有關(guān)。一個(gè)模塊可以有多個(gè)文件,一個(gè)文件也可以有多個(gè)模塊:
module Foo
include("file1.jl")
include("file2.jl")
end
在不同的模塊中包含同樣的代碼,會(huì)帶來(lái)類(lèi)似 mixin 的特征。可以利用這點(diǎn),在不同的環(huán)境定義下運(yùn)行同樣的代碼,例如運(yùn)行一些操作的“安全”版本來(lái)進(jìn)行代碼測(cè)試:
module Normal
include("mycode.jl")
end
module Testing
include("safe_operators.jl")
include("mycode.jl")
end
有三個(gè)重要的標(biāo)準(zhǔn)模塊:Main, Core, 和 Base。
Main 是頂級(jí)模塊,Julia 啟動(dòng)時(shí)將 Main 設(shè)為當(dāng)前模塊。提示符模式下,變量都是在 Main 模塊中定義,whos()
可以列出 Main 中的所有變量。
Core 包含“內(nèi)置”的所有標(biāo)志符,例如部分核心語(yǔ)言,但不包括庫(kù)。每個(gè)模塊都隱含地調(diào)用了 using Core
,因?yàn)闆](méi)有這些聲明,什么都做不了。
Base 是標(biāo)準(zhǔn)庫(kù)( 在 base/ 文件夾下)。所有的模塊都隱含地調(diào)用了 using Base
,因?yàn)榇蟛糠智闆r下都需要它。
除了 using Base
,模塊顯式引入了所有的運(yùn)算符。模塊還自動(dòng)包含 eval
函數(shù)的定義,這個(gè)函數(shù)對(duì)本模塊中的表達(dá)式求值。
如果不想要這些定義,可以使用 baremodule
關(guān)鍵字來(lái)定義模塊。使用 baremodule
時(shí),一個(gè)標(biāo)準(zhǔn)的模塊有如下格式:
baremodule Mod
using Base
importall Base.Operators
eval(x) = Core.eval(Mod, x)
eval(m,x) = Core.eval(m, x)
...
end
輸入指令 using foo
, Julia 會(huì)首先在 Main
名字空間中尋找 Foo
。如果模塊未找到, Julia 會(huì)嘗試 require("Foo")
。通常情況下, 這會(huì)從已安裝的包中載入模塊。
然而,有些模塊還有子模塊,也就是說(shuō),有時(shí)候不能從 Main
中直接引用一些模塊。有兩種方法可以解決這個(gè)問(wèn)題:方法一,使用絕對(duì)路徑,如 using Base.Sort
。方法二,使用相對(duì)路徑,這樣可以方便地載入當(dāng)前模塊的子模塊或者嵌套的模塊:
module Parent
module Utils
...
end
using .Utils
...
end
模塊 Parent
包含子模塊 Utils
。如果想要 Utils
中的內(nèi)容對(duì) Parent
可見(jiàn), 可以使用 using
加上英文句號(hào)。更多的句號(hào)表示在更下一層的命名空間進(jìn)行搜索。例如,using ..Utils
將會(huì)在 Parent
模塊的
子模塊內(nèi)尋找 Utils
。
全局變量 LOAD_PATH
包含了調(diào)用 require
時(shí) Julia搜索模塊的目錄??梢杂?push!
進(jìn)行擴(kuò)展 :
push!(LOAD_PATH, "/Path/To/My/Module/")
將這一段代碼放在 ~\.juliarc.jl
里能夠在每次 Julia啟動(dòng)時(shí)對(duì) LOAD_PATH
擴(kuò)展。此外,還可以通過(guò)定義環(huán)境變量
JULIA_LOAD_PATH
來(lái)擴(kuò)展 Julia 的模塊路徑。
如果一個(gè)命名是有許可的(qualified)(如 Base.sin
),即使它沒(méi)被 export ,仍能被外部讀取。這在調(diào)試時(shí)非常有用。
import 或 export 宏時(shí),要在宏名字前添加 @
符號(hào),例如 import Mod.@mac
。在其他模塊中的宏可以被調(diào)用為 Mod.@mac
或 @Mod.mac
。
形如 M.x = y
的語(yǔ)法是錯(cuò)的,不能給另一個(gè)模塊中的全局變量賦值;全局變量的賦值都是在變量所在的模塊中進(jìn)行的。
直接在頂層聲明為 global x
,可以將變量聲明為“保留”的。這可以用來(lái)防止加載時(shí),全局變量初始化遇到命名沖突。
更多建議: