排程元組型別
因為 Julia 函式引數列表本身是元組,所以通過方法引數本身更容易排程各種元組,通常使用 splatting``...
運算子的自由使用。例如,從 Base
開始考慮 reverse
對元組的實現:
revargs() = ()
revargs(x, r...) = (revargs(r...)..., x)
reverse(t::Tuple) = revargs(t...)
以這種方式在元組上實現方法可以保持型別穩定性 ,這對效能至關重要。我們可以看到使用 @code_warntype
巨集的方法沒有開銷:
julia> @code_warntype reverse((1, 2, 3))
Variables:
#self#::Base.#reverse
t::Tuple{Int64,Int64,Int64}
Body:
begin
SSAValue(1) = (Core.getfield)(t::Tuple{Int64,Int64,Int64},2)::Int64
SSAValue(2) = (Core.getfield)(t::Tuple{Int64,Int64,Int64},3)::Int64
return (Core.tuple)(SSAValue(2),SSAValue(1),(Core.getfield)(t::Tuple{Int64,Int64,Int64},1)::Int64)::Tuple{Int64,Int64,Int64}
end::Tuple{Int64,Int64,Int64}
雖然有點難以閱讀,但這裡的程式碼只是分別建立一個包含原始元組的第 3,第 2 和第 1 個元素值的新元組。在許多機器上,這可以編譯為極其高效的 LLVM 程式碼,它由載入和儲存組成。
julia> @code_llvm reverse((1, 2, 3))
define void @julia_reverse_71456([3 x i64]* noalias sret, [3 x i64]*) #0 {
top:
%2 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 1
%3 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 2
%4 = load i64, i64* %3, align 1
%5 = load i64, i64* %2, align 1
%6 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 0
%7 = load i64, i64* %6, align 1
%.sroa.0.0..sroa_idx = getelementptr inbounds [3 x i64], [3 x i64]* %0, i64 0, i64 0
store i64 %4, i64* %.sroa.0.0..sroa_idx, align 8
%.sroa.2.0..sroa_idx1 = getelementptr inbounds [3 x i64], [3 x i64]* %0, i64 0, i64 1
store i64 %5, i64* %.sroa.2.0..sroa_idx1, align 8
%.sroa.3.0..sroa_idx2 = getelementptr inbounds [3 x i64], [3 x i64]* %0, i64 0, i64 2
store i64 %7, i64* %.sroa.3.0..sroa_idx2, align 8
ret void
}