简体   繁体   English

制作无参数类型具有“默认值”

[英]Making a no parameter type have “defaults”

I essentially want to do the following: 我基本上想要做以下事情:

typealias CVODE_BDF CVODE_BDF{:Newton,:Dense}

that is, allow a user to pass to my function CVODE_BDF and, if they did not set any of the type parameters, interpret it as CVODE_BDF{:Newton,:Dense} . 也就是说,允许用户传递给我的函数CVODE_BDF ,如果他们没有设置任何类型参数,则将其解释为CVODE_BDF{:Newton,:Dense} I know that the typealias doesn't actually work, but is there a way to simulate this? 我知道typealias实际上不起作用,但有没有办法模拟这个? Like in the function, read T.parameters[1] and somehow see that it was empty? 就像在函数中一样,读取T.parameters[1]并以某种方式看到它是空的?

You can do this if the function accepts objects of that type , rather than the type itself. 如果函数接受该类型的对象而不是类型本身,则可以执行此操作。 Eg 例如

type MyObject{T}
end


const DefaultMyObject = MyObject{Int64}()

f{T}(x::MyObject{T}=DefaultMyObject) = T

f(), f(MyObj{Float64}())

gives

(Int64,Float64)

One possibility is setting the type parameters ( {:Newton,:Dense} ) via Constructors . 一种可能性是通过构造函数设置类型参数( {:Newton,:Dense} )。

Here is an example of the rational number type defined in Julia (rational.jl): 以下是Julia(rational.jl)中定义的有理数字类型的示例:

immutable Rational{T<:Integer} <: Real
    num::T
    den::T

    function Rational(num::T, den::T)
        if num == 0 && den == 0
            error("invalid rational: 0//0")
        end
        g = gcd(den, num)
        num = div(num, g)
        den = div(den, g)
        new(num, den)
    end
end

In your example, you could define a constructor function in you CVODE_BDF type definition and check for the types and fall back to {:Newton,:Dense} if they are not set. 在您的示例中,您可以在CVODE_BDF类型定义中定义构造函数并检查类型,如果未设置则返回{:Newton,:Dense}

Would something like this work for you? 这样的事情对你有用吗?

type A{T, S} end

Function implementation: 功能实现:

f{T, S}(::Type{A{T,S}}) = T, S  

Wrappers that set the default values: 设置默认值的包装器:

f(::Type{A}) = f(A{1, 1})
f{T}(::Type{A{T}}) = f(A{T, 1})
f{S}(::Type{A{:default, S}}) = f(A{1, S})

Result: 结果:

f(A)                 # (1,1)
f(A{3,4})            # (3,4)
f(A{0})              # (0,1)
f(A{:default, 2})    # (1,2)

Because the last call is a bit ugly, objects are probably the better choice if maximum flexibility is needed. 因为最后一次调用有点难看,如果需要最大的灵活性,对象可能是更好的选择。 Additionally, constructors can enforce constraints on the parameters, so that they don't need to be checked in the function. 此外,构造函数可以对参数强制执行约束,因此不需要在函数中检查它们。

Edit: 编辑:

If your function has more than one argument, adding methods for every combination of parameters is too much work. 如果你的函数有多个参数,那么为每个参数组合添加方法就太多了。 Instead, one can define a default method for each type (just one parameter for brevity): 相反,可以为每种类型定义一个默认方法(为简洁起见,只需一个参数):

type A{T} end
type B{T} end

default{T}(::Type{A{T}}) = A{T}
default(::Type{A}) = A{1}
default{T}(::Type{B{T}}) = B{T}
default(::Type{B}) = B{1}

f{T,S}(::Type{A{T}}, ::Type{B{S}}) = T*S
f{T<:A, S<:B}(a::Type{T}, b::Type{S}) = f(default(a), default(b))

On a current nightly, this has no runtime overhead: 在当前的夜晚,这没有运行时开销:

julia> @code_llvm f(A,B)

define i64 @julia_f_62099(%jl_value_t*, %jl_value_t*) #0 {
top:
  ret i64 1
}

Yes there is. 就在这里。 If you do Type{CVODE_BDF} you can then check the resulting object's parameters. 如果您Type{CVODE_BDF} ,则可以检查生成的对象的参数。 If CVODE_BDF was 'empty' this will return a CVODE_BDF type with generic parameters, otherwise they will be the specific ones used. 如果CVODE_BDF为“空”,则返回带有通用参数的CVODE_BDF类型,否则它们将是使用的特定参数。

Example (using Array since I don't have CVODE_BDF handy): 示例(使用Array因为我没有方便的CVODE_BDF ):

julia> Type{Array}.parameters
svec(Array{T,N})

julia> Type{Array{Float64, Int64}}.parameters
svec(Array{Float64,Int64})

Example function: 功能示例:

function f{T}(t::T)
  if Type(t).parameters == Type(Array).parameters
    t = Array{Int64, 1};
  end
  return t;
end

julia> f(Array{Int64, 1})
Array{Int64,1}

julia> f(Array{Float64, 1})
Array{Float64,1}

julia> f(Array)
Array{Int64,1}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM