不可變型別

最簡單的複合型別是不可變型別。不可變型別的例項(如元組 )是值。它們的欄位在建立後無法更改。在許多方面,不可變型別就像 Tuple,它具有型別本身和每個欄位的名稱。

單例型別

根據定義,複合型別包含許多更簡單的型別。在朱莉婭,這個數字可以為零; 也就是說,允許不可變型別包含任何欄位。這與空元組 () 相當。

為什麼這有用呢?這種不可變型別被稱為單例型別,因為它們中只有一個例子可能存在。這些型別的值稱為單值。標準庫 Base 包含許多這樣的單例型別。這是一個簡短的清單:

  • Voidnothing 的型別。我們可以驗證 Void.instance(這是檢索單例型別的單例值的特殊語法)確實是 nothing
  • 任何媒體型別,例如 MIME"text/plain",都是具有單個例項 MIME("text/plain") 的單例型別。
  • Irrational{:π}Irrational{:e}Irrational{:φ} 和類似型別是單例型別,它們的單例例項是無理值π = 3.1415926535897... 等。
  • 迭代器大小特徵 Base.HasLengthBase.HasShapeBase.IsInfiniteBase.SizeUnknown 都是單例型別。

Version >= 0.5.0

  • 在 0.5 及更高版本中,每個函式都是單例型別的單例例項! 像任何其他單例值一樣,我們可以從 typeof(sin).instance 恢複函式 sin

由於它們不包含任何內容,因此單例型別非常輕量級,並且編譯器可以經常對它們進行優化,以避免執行時開銷。因此,它們非常適合於特徵,特殊標記值以及人們想要專注的功能。

要定義單例型別,

julia> immutable MySingleton end

要為單例型別定義自定義列印,

julia> Base.show(io::IO, ::MySingleton) = print(io, "sing")

要訪問單例例項,

julia> MySingleton.instance
MySingleton()

通常,人們會將此指定為常數:

julia> const sing = MySingleton.instance
MySingleton()

包裝型別

如果零欄位不可變型別是有趣且有用的,那麼也許單欄位不可變型別甚至更有用。這些型別通常稱為包裝器型別,因為它們包裝一些底層資料,為所述資料提供備用介面。Base 中包裝型別的一個例子是 String 。我們將定義一個類似於 String 的型別,命名為 MyString。這種型別將由位元組的向量(一維陣列 )支援(UInt8)。

首先,型別定義本身和一些自定義顯示:

immutable MyString <: AbstractString
    data::Vector{UInt8}
end

function Base.show(io::IO, s::MyString)
    print(io, "MyString: ")
    write(io, s.data)
    return
end

現在我們的 MyString 型已經可以使用了! 我們可以為它提供一些原始的 UTF-8 資料,並按我們喜歡的方式顯示:

julia> MyString([0x48,0x65,0x6c,0x6c,0x6f,0x2c,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21])
MyString: Hello, World!

顯然,這種字串型別在變得像 Base.String 型別一樣可用之前需要做很多工作。

真正的複合型別

也許最常見的是,許多不可變型別包含多個欄位。一個例子是標準庫 Rational{T} 型別,它包含兩個 fieds:分子的 num 欄位和分母的 den 欄位。模擬這種型別的設計相當簡單:

immutable MyRational{T}
    num::T
    den::T
    MyRational(n, d) = (g = gcd(n, d); new(n÷g, d÷g))
end
MyRational{T}(n::T, d::T) = MyRational{T}(n, d)

我們已成功實現了一個簡化有理數的建構函式:

julia> MyRational(10, 6)
MyRational{Int64}(5,3)