2016-02-19 50 views
4

說,我有一個類型層次不穩定型和工廠構造

abstract A 
immutable B <: A end 
immutable C <: A end 

A構造如下工廠模式:

function A(x::Int) 
    if x > 0 
     B() 
    else 
     C() 
    end 
end 

它作爲預期收益基礎上,輸入不同的亞型。但是,它也是不穩定的,因爲我找不到強制返回類型爲A的方法。

那麼,這裏有工廠模式不好嗎?類型不穩定性隻影響不可變類型而不是可變類型,因爲後者是引用類型。

我必須爲此選擇參數類型嗎?

immutable D{T <: A} 
    type::T 
end 

function D(x::Int) 
    if x > 0 
     D(B()) 
    else 
     D(C()) 
    end 
end 

這感覺有點不好。

其實,類型不穩定的函數有多糟?是否值得交換更好的代碼可讀性?

或者,我應該定義typealias A Union{B,C}而不是?

回答

5

嗯,你可以這樣做:

function A(x::Int) 
    if x > 0 
     B()::A 
    else 
     C()::A 
    end 
end 

,但它並不能幫助:

julia> @code_warntype A(5) 
Variables: 
    x::Int64 

Body: 
    begin # none, line 2: 
     unless (Base.slt_int)(0,x::Int64)::Bool goto 0 # none, line 3: 
     return $(Expr(:new, :((top(getfield))(Main,:B)::Type{B}))) 
     goto 1 
     0: # none, line 5: 
     return $(Expr(:new, :((top(getfield))(Main,:C)::Type{C}))) 
     1: 
    end::Union{B,C} 

不能創建一個抽象類型的實例。此外,在當前的Julia中,任何抽象類型都會自動「類型不穩定」,這意味着編譯器無法爲其生成優化的代碼。所以不存在「迫使返回類型爲A」這樣的事情,然後以某種方式讓函數類型穩定(就獲得很好的性能而言)。

您可以實現類型穩定的工廠模式,但輸出類型應該由輸入類型決定,而不是輸入值。例如:

A(x::Vector) = B() 
A(x::Matrix) = C() 

A層次結構的對象的類型穩定構造函數。

如果沒有明顯的類型用來顯示你的意圖,你可以隨時使用Val

A(x, ::Type{Val{1}}) = B() 
A(x, ::Type{Val{2}}) = C() 

A(1, Val{1}) # returns B() 
A(1, Val{2}) # returns C()