Julia 为什么我们需要'iteratoreltype()`?
我不知道为什么需要Julia 为什么我们需要'iteratoreltype()`?,julia,Julia,我不知道为什么需要IteratorEltype()。每个iterable都保证生成类型为Any的对象,因此如果您不知道任何更好的方法,那么您可以始终默认使用该方法。区分“我知道它可能是任何东西”(IteratorEltype==HasEltype&&eltype=Any)和“我不知道它是什么,因此它可能是任何东西”(IteratorEltype==EltypeUnknown)有什么意义 在Base Julia中,我能找到的唯一使用EltypeUnknown()的类型是Generator,它是(i
IteratorEltype()
。每个iterable都保证生成类型为Any
的对象,因此如果您不知道任何更好的方法,那么您可以始终默认使用该方法。区分“我知道它可能是任何东西”(IteratorEltype==HasEltype&&eltype=Any
)和“我不知道它是什么,因此它可能是任何东西”(IteratorEltype==EltypeUnknown
)有什么意义
在Base Julia中,我能找到的唯一使用
EltypeUnknown()
的类型是Generator
,它是(iter中的f(I)for I)
语法背后的工具。我可以想象,如果eltype(iter)
是非叶型的,那么很难/不可能找到这样一个生成器的eltype
,但是在这种情况下,不简单地将eltype
设置为Any
有什么好处呢?当然,如果eltype(iter)
是叶子类型,而f
是类型稳定的,那么您不希望它是Any
,但这两种情况在编译时应该是可以区分的 这两个IteratorEltype()
选项之间的区别如下所示:
表示迭代器的值应被视为类型为HasEltype()
的对象,即使eltype()
比迭代器中实际遇到的类型更一般eltype()
要求像EltypeUnknown()
这样的函数找出适用于所有元素的最具体类型collect()
示例:
julia> abstract type Wrapper end
Base.length(w::Wrapper) = length(w.data)
Base.iterate(w::Wrapper, s...) = iterate(w.data, s...)
struct EltypeWrapper{T,D} <: Wrapper
data::D
end
EltypeWrapper{T}(data) where T = EltypeWrapper{T,typeof(data)}(data)
Base.eltype(::Type{<:EltypeWrapper{T}}) where T = T
struct EltypeUnknownWrapper{D} <: Wrapper
data::D
end
Base.IteratorEltype(::Type{<:EltypeUnknownWrapper}) = Base.EltypeUnknown()
julia> collect(EltypeWrapper{Any}(Any[1,2.0]))
2-element Array{Any,1}:
1
2.0
julia> collect(EltypeUnknownWrapper(Any[1,2.0]))
2-element Array{Real,1}:
1
2.0
IteratorEltype()。如果对叶类型进行操作,几乎所有代码的速度都会快上一个数量级,因此在中可以更快地将EltypeUnknown()
作为IteratorEltype()
,并希望eltype()
归结为具体类型,而不是设置IteratorEltype()=HasEltype()
,然后设置eltype()
到某个抽象类型。在base
目录中的快速grep
显示array.jl
和reduce.jl
使用iteratoreltype
。出于编译时优化和决策的原因。是的,但这种方法究竟能优化什么呢?
julia> using BenchmarkTools
abstract type AbstractIterable end
struct TypedIterable <: AbstractIterable; end
struct UntypedIterable <: AbstractIterable; end
Base.length(::AbstractIterable) = 100000
Base.eltype(::Type{TypedIterable}) = Int
Base.IteratorEltype(::Type{UntypedIterable}) = Base.EltypeUnknown()
function Base.iterate(f::AbstractIterable,i = 1)
i > length(f) && return nothing
return i, i+1
end
@btime collect(UntypedIterable())
@btime collect(TypedIterable())
;
43.033 μs (2 allocations: 781.33 KiB)
56.772 μs (2 allocations: 781.33 KiB)