Julia 是否可以表示依赖于其他参数化类型的字段类型?

Julia 是否可以表示依赖于其他参数化类型的字段类型?,julia,Julia,作为一个人工示例,假设我有一个参数结构,其中T主要用于这些用例: julia> const CounterType = Union{UInt16, UInt32, UInt64} Union{UInt16, UInt32, UInt64} julia> mutable struct Summary{T<:AbstractFloat, S<:CounterType} count::S sum::T func

作为一个人工示例,假设我有一个参数结构,其中
T主要用于这些用例:

julia> const CounterType = Union{UInt16, UInt32, UInt64}
Union{UInt16, UInt32, UInt64}

julia> mutable struct Summary{T<:AbstractFloat, S<:CounterType}
           count::S
           sum::T
           function Summary{T}() where {T<:AbstractFloat}
               S = T === Float16 ? UInt16 : 
                   T === Float32 ? UInt32 :
                   T === Float64 ? UInt64 : throw(ArgumentError("unexpected type: $(T)!"))
               new{T,S}(zero(S), zero(T))
           end
       end

julia> Summary() = Summary{Float64}()
Summary

julia> function avg(summary::Summary{T})::T where {T <: AbstractFloat}
       if summary.count > zero(summary.count)
           summary.sum / summary.count
       else
           zero(T)
       end
   end
avg (generic function with 1 method)

julia> avg(Summary())
0.0

julia> @code_warntype avg(Summary())
Body::Float64
1 ─ %1 = (Base.getfield)(summary, :count)::UInt64
│   %2 = (Base.ult_int)(0x0000000000000000, %1)::Bool
└──      goto #3 if not %2
2 ─ %4 = (Base.getfield)(summary, :sum)::Float64
│   %5 = (Base.getfield)(summary, :count)::UInt64
│   %6 = (Base.uitofp)(Float64, %5)::Float64
│   %7 = (Base.div_float)(%4, %6)::Float64
└──      return %7
3 ─      return 0.0

julia> @code_warntype avg(Summary{Float32}())
Body::Float32
1 ─ %1 = (Base.getfield)(summary, :count)::UInt32
│   %2 = (Base.ult_int)(0x00000000, %1)::Bool
└──      goto #3 if not %2
2 ─ %4 = (Base.getfield)(summary, :sum)::Float32
│   %5 = (Base.getfield)(summary, :count)::UInt32
│   %6 = (Base.uitofp)(Float32, %5)::Float32
│   %7 = (Base.div_float)(%4, %6)::Float32
└──      return %7
3 ─      return 0.0f0
julia>const CounterType=Union{UInt16,UInt32,UInt64}
联合体{UInt16,UInt32,UInt64}
julia>可变结构摘要{T平均值(摘要())
0
julia>@code\u warntype平均值(Summary())
Body::Float64
1.─ %1=(Base.getfield)(摘要:计数):UInt64
│   %2=(Base.ult_int)(0x0000000000000000,%1)::Bool
└──      转到3如果不是%2
2.─ %4=(Base.getfield)(摘要:sum)::Float64
│   %5=(Base.getfield)(摘要:计数):UInt64
│   %6=(Base.uitofp)(Float64,%5)::Float64
│   %7=(基本div_float)(%4,%6)::Float64
└──      返回%7
3.─      返回0.0
julia>@code_warntype avg(摘要{Float32}())
正文::Float32
1.─ %1=(Base.getfield)(摘要:计数):UInt32
│   %2=(Base.ult_int)(0x00000000,%1)::Bool
└──      转到3如果不是%2
2.─ %4=(Base.getfield)(摘要:sum)::Float32
│   %5=(Base.getfield)(摘要:计数):UInt32
│   %6=(Base.uitofp)(Float32,%5)::Float32
│   %7=(基本div_float)(%4,%6)::Float32
└──      返回%7
3.─      返回0.0f0

+1 niat!IIUC,Float32 avg()调用需要在UInt32和UInt64之间转换,以便与0进行比较(
(Core.zext_int)(Core.UInt64,%1)::UInt64
)。出于好奇,这可以避免吗?是的。
summary.count>zero(summary.count)
module SummaryStats

export Summary, avg

const CounterType = Union{UInt16, UInt32, UInt64}

mutable struct Summary{T<:AbstractFloat}

    count::CounterType
    sum::T
    # explicitly typed no-arg constructor
    Summary{T}() where {T<:AbstractFloat} = new(_counter(T), zero(T))
end

# untyped no-arg constructor defaults to Float64
Summary() = Summary{Float64}()

function avg(summary::Summary{T})::T where {T <: AbstractFloat}
    if summary.count > zero(_counter(typeof(T)))
        summary.sum / summary.count
    else
        zero(T)
    end
end

# internal helper functions, not exported
Base.@pure _counter(::Type{Float16})::UInt16 = UInt16(0)
Base.@pure _counter(::Type{Float32})::UInt32 = UInt32(0)
Base.@pure _counter(::DataType)::UInt64 = UInt64(0)

end # module
julia> const CounterType = Union{UInt16, UInt32, UInt64}
Union{UInt16, UInt32, UInt64}

julia> mutable struct Summary{T<:AbstractFloat, S<:CounterType}
           count::S
           sum::T
           function Summary{T}() where {T<:AbstractFloat}
               S = T === Float16 ? UInt16 : 
                   T === Float32 ? UInt32 :
                   T === Float64 ? UInt64 : throw(ArgumentError("unexpected type: $(T)!"))
               new{T,S}(zero(S), zero(T))
           end
       end

julia> Summary() = Summary{Float64}()
Summary

julia> function avg(summary::Summary{T})::T where {T <: AbstractFloat}
       if summary.count > zero(summary.count)
           summary.sum / summary.count
       else
           zero(T)
       end
   end
avg (generic function with 1 method)

julia> avg(Summary())
0.0

julia> @code_warntype avg(Summary())
Body::Float64
1 ─ %1 = (Base.getfield)(summary, :count)::UInt64
│   %2 = (Base.ult_int)(0x0000000000000000, %1)::Bool
└──      goto #3 if not %2
2 ─ %4 = (Base.getfield)(summary, :sum)::Float64
│   %5 = (Base.getfield)(summary, :count)::UInt64
│   %6 = (Base.uitofp)(Float64, %5)::Float64
│   %7 = (Base.div_float)(%4, %6)::Float64
└──      return %7
3 ─      return 0.0

julia> @code_warntype avg(Summary{Float32}())
Body::Float32
1 ─ %1 = (Base.getfield)(summary, :count)::UInt32
│   %2 = (Base.ult_int)(0x00000000, %1)::Bool
└──      goto #3 if not %2
2 ─ %4 = (Base.getfield)(summary, :sum)::Float32
│   %5 = (Base.getfield)(summary, :count)::UInt32
│   %6 = (Base.uitofp)(Float32, %5)::Float32
│   %7 = (Base.div_float)(%4, %6)::Float32
└──      return %7
3 ─      return 0.0f0