排程型別
在 Julia 上,你可以為每個函式定義多個方法。假設我們定義了三個相同函式的方法:
foo(x) = 1
foo(x::Number) = 2
foo(x::Int) = 3
在決定使用什麼方法(稱為排程 )時,Julia 選擇與引數型別匹配的更具體的方法:
julia> foo('one')
1
julia> foo(1.0)
2
julia> foo(1)
3
這有利於多型性 。例如,我們可以通過定義兩個名為 Nil
和 Cons
的不可變型別輕鬆建立連結串列 。這些名稱傳統上分別用於描述空列表和非空列表。
abstract LinkedList
immutable Nil <: LinkedList end
immutable Cons <: LinkedList
first
rest::LinkedList
end
我們將通過 Nil()
和 Cons(first, rest)
的任何其他列表來表示空列表,其中 first
是連結串列的第一個元素,rest
是由所有剩餘元素組成的連結串列。例如,列表 [1, 2, 3]
將表示為
julia> Cons(1, Cons(2, Cons(3, Nil())))
Cons(1,Cons(2,Cons(3,Nil())))
清單是空的嗎?
假設我們想要擴充套件標準庫的 isempty
函式,該函式適用於各種不同的集合:
julia> methods(isempty)
# 29 methods for generic function "isempty":
isempty(v::SimpleVector) at essentials.jl:180
isempty(m::Base.MethodList) at reflection.jl:394
...
我們可以簡單地使用函式排程語法,並定義 isempty
的另外兩種方法。由於此功能來自 Base
模組,因此我們必須將其限定為 Base.isempty
才能擴充套件它。
Base.isempty(::Nil) = true
Base.isempty(::Cons) = false
在這裡,我們根本不需要引數值來確定列表是否為空。僅僅型別就足以計算該資訊。如果我們不需要使用它們的值,Julia 允許我們省略引數的名稱,只保留它們的型別註釋。
我們可以測試我們的 isempty
方法是否有效:
julia> using Base.Test
julia> @test isempty(Nil())
Test Passed
Expression: isempty(Nil())
julia> @test !isempty(Cons(1, Cons(2, Cons(3, Nil()))))
Test Passed
Expression: !(isempty(Cons(1,Cons(2,Cons(3,Nil())))))
事實上,isempty
的方法數量增加了 14:
julia> methods(isempty)
# 31 methods for generic function "isempty":
isempty(v::SimpleVector) at essentials.jl:180
isempty(m::Base.MethodList) at reflection.jl:394
顯然,確定連結串列是否為空是一個簡單的例子。但它導致更有趣的事情:
這份清單有多長?
標準庫中的 length
函式為我們提供了集合或某些可迭代的長度。有很多方法可以為連結串列實現 length
。特別是,在 Julia 中使用 while
迴圈可能是最快且最節省記憶體的。但是要避免過早優化 ,所以讓我們假設我們的連結串列無需高效。編寫 length
函式最簡單的方法是什麼?
Base.length(::Nil) = 0
Base.length(xs::Cons) = 1 + length(xs.rest)
第一個定義很簡單:空列表的長度為 0
。第二個定義也很容易理解:為了計算列表的長度,我們計算第一個元素,然後計算列表其餘部分的長度。我們可以像測試 isempty
一樣測試這種方法:
julia> @test length(Nil()) == 0
Test Passed
Expression: length(Nil()) == 0
Evaluated: 0 == 0
julia> @test length(Cons(1, Cons(2, Cons(3, Nil())))) == 3
Test Passed
Expression: length(Cons(1,Cons(2,Cons(3,Nil())))) == 3
Evaluated: 3 == 3
下一步
這個玩具示例遠非實現連結列表中所需的所有功能。例如,它缺少迭代介面。但是,它說明了如何使用 dispatch 編寫簡短明瞭的程式碼。