如何在不收集元素/分配内存的情况下实现自定义迭代器的`last`方法?
自定义迭代器获取最后元素的解决方案
先回顾问题中的Squares迭代器实现:
struct Squares count::Int end Base.iterate(S::Squares, state=1) = state > S.count ? nothing : (state*state, state+1) Base.eltype(::Type{Squares}) = Int Base.length(S::Squares) = S.count
虽然定义了length方法,但调用last(Squares(5))会报错——因为Julia默认的last实现依赖lastindex方法,而我们的类型未定义该方法。
无需collect的解决方案
存在两种无需分配内存的方法获取最后元素:
1. 实现lastindex与getindex方法
如果希望让类型支持索引访问,同时兼容last函数,可以补充实现这两个方法:
Base.lastindex(S::Squares) = S.count Base.getindex(S::Squares, i::Int) = i*i
此时调用last(Squares(5))会通过lastindex拿到最后位置,再用getindex计算对应值,返回25,全程无内存分配。
2. 直接扩展Base.last方法
对于Squares这种可以直接推导最后元素的类型,直接实现last方法更高效简洁:
Base.last(S::Squares) = S.count * S.count
调用last(Squares(5))会直接返回25,完全跳过索引逻辑,性能最优。
扩展Base.last是否合适?
完全合适。对于有明确最后元素计算方式的自定义类型,直接实现last方法比依赖索引逻辑更符合类型语义,同时能避免不必要的计算开销。尤其是迭代器类型,如果无需遍历就能得到最后元素,直接扩展last是最优选择。
内容的提问来源于stack exchange,提问作者Alec
相关产品推荐
相关产品推荐

