多重分派(multiple dispatch)是 Julia 語言中相當重要的程式典範。多重分派的例子在 Julia 的套建中相當多見,其中一個應用就是用來取代型別檢查。

在一般的程式中有相當多的型別檢查的片段,在 Julia 中可能會寫成這樣:

1
2
3
4
5
6
7
8
9
function foo(x)
if x isa Int
# do something
elseif x isa String
# do another things
elseif x isa Float64
# do other things
end
end

在 Julia 中這樣寫當然是可以,但是這樣就失去了用 Julia 的優勢,可以將他用多重分派進行改寫。

1
2
3
4
5
6
7
8
9
10
11
function foo(x::Int)
# do something
end

function foo(x::String)
# do another things
end

function foo(x::Float64)
# do other things
end

看起來好像只是將他分成三隻函式而已,沒什麼了不起的吧?

不不不,光是將他分成三隻函式,就足以讓 if...else 結構中的程式馬可以分別被編譯,成為效能更好的程式碼。在編譯的過程中,也由於有充足的引數型別的資訊,所以會編譯出更好的程式。

更值得一提的是,在軟體工程上也是有好處的,他符合軟體工程的開放封閉原則,對新增功能開放、對修改現有功能關閉,要支援新的型別只需要增加新的函式,並不用去修改現有的 if...else 結構,可以避免新增功能的同時去動到舊有的功能。

在演算法上也可以依據不同的型別做分離,可以將他看能完全不同的演算法,演算法之間不會混雜在一起。

所以這就是善用 Julia 的多重分派來改寫型別檢查的範例。

留言與分享

一般我們會在函式的引數上加上參數,這樣可以讓函式去推論引數的型別,這樣有多種用途,其中之一當然是增進效能。

1
2
3
4
5
julia> foo(a::T) where {T} = zero(T)
foo (generic function with 1 method)

julia> foo(5)
0

那我們有沒有辦法對回傳值的型別做參數化呢?

有的,可以這樣做。

1
2
3
4
5
julia> (foo(a::T)::T) where {T} = zero(T)
foo (generic function with 1 method)

julia> foo(5)
0

一般要標記回傳值的型別,要寫在整個 function signature 的後面,也就是

1
foo(a)::Int

如果要將他標記為參數,那就需要寫成

1
(foo(a)::T) where {T}

這樣就寫出來啦!!

留言與分享

  • 第 1 頁 共 1 頁

Yueh-Hua Tu

目標是計算生物學家!
Systems Biology, Computational Biology, Machine Learning
Julia Taiwan 發起人


研發替代役研究助理


Taiwan