1、简介
julia提供的各种接口为自定义类型扩展功能。
本文讨论一下Iteration接口。自定义的类型实现这里接口就可以实现迭代功能,也就是可以直接在for循环这样使用:假如iter是你的自定义类型:for i in iter # or "for i = iter" # bodyend
等同于:
next = iterate(iter)while next !== nothing (i, state) = next # body next = iterate(iter, state)end
2、如何实现
要实现Iteration接口需要实现iterate(iter, state)方法,这个方法在Base包里面,它的含义是返回iter的下一个元素和其状态state,如果没有就返回nothing, state可以是索引。
我们定义一个类型Squares,它有一个count域:struct Squares count::Int end
然后定义他的iterate方法,要显性的指定报名:
Base.iterate(S::Squares, state=1) = state > S.count ? nothing : (state*state, state+1)
state小于count是计算它的平方值,然后+1,否则返回nothing。
定义好之后用for循环迭代如下:
julia> for i in Squares(5) println(i) end1491625
3、其他与迭代相关方法
实现了iterable后还可以使用其他相关的函数, 如 in (检查元素是否在集合中) 、 mean(求平均数) 和 std (求方差),后两个函数在Statistics包里:
julia> 25 in Squares(10)truejulia> using Statisticsjulia> mean(Squares(3))4.666666666666667julia> std(Squares(100))3024.355854282583
4、实现其他迭代集合方法
我们还可以为Squares实现其他与迭代集合有关的方法:
eltype(返回集合元素类型), length(返回集合元素个数),julia> Base.eltype(::Type{Squares}) = Int # Note that this is defined for the typejulia> Base.length(S::Squares) = S.countjulia> sum(Squares(100))338350
默认的sum方法是通过循环迭代计算所有元素的和:
我们可以重新实现sum方法使其更高效,使用公式直接求和julia> Base.sum(S::Squares) = (n = S.count; return n*(n+1)*(2n+1)÷6)julia> sum(Squares(1803))1955361914
5.反向迭代
要实现反向迭代,需要实现Iterators.Reverse{T}的iterate方法,T指类型,这里我们实现Iterators.Reverse{Squares},
collect收集集合元素,也可以用for迭代:julia> Base.iterate(rS::Iterators.Reverse{Squares}, state=rS.itr.count) = state < 1 ? nothing : (state*state, state-1)julia> collect(Iterators.reverse(Squares(4)))4-element Array{Int64,1}: 16 9 4 1 julia> for i in Iterators.reverse(Squares(5)) println(i) end2516941