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