2016-02-19 48 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()