How to create custom iterator for Range
I'd like to create a subclass of Range in order to specify a step size other than 1 so I can do things like:
>> a = RangeWithStepSize.new(-1, 2, 0.5).each {|x| puts(x)}
-1.0
-0.5
0.0
0.5
1.0
1.5
2.0
=> -1..2
My first attempt at an implementation doesn't work:
class RangeWithStepSize < Range
attr_reader :step_size
def initialize(start_v, end_v, step_size, exclusive = false)
super(start_v, end_v, exclusive)
@step_size = step_size
end
def each
self.step(step_size).each
end
end
>> a = RangeWithStepSize.new(-1, 2, 0.5).each {|x| puts(x)}
=> #<Enumerator: [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]:each>
It appears that RangeWithStepSize#each is returning a valid enumerator, but it doesn't enumerate. Any idea why?
<aside>
This may be related, but I notice is that Range#step without a block does NOT return an enumerator as specified in the documentation; it returns an array instead:
>> Range.n开发者_如何转开发ew(-1, 2).step(0.5).class
=> Array
An Array is enumerable, but it is not an Enumerator. Is this a documentation bug?</aside>
clarification
I'd like to make a version of Range that encapsulates a step size, so I can do:
a = RangeWithStepSize(-1, 2, 0.5)
b = RangeWithStepSize(-1, 2, 0.25)
... so enumerating on a produces a step size of 0.5 and b produces 0.25.
You know you can do this, right? Inheritance isn't necessary here.
(-1..2).step(0.5) do |x|
puts x
end
Your code will work with a few small adjustments:
class RangeWithStepSize < Range
attr_reader :step_size
def initialize(start_v, end_v, step_size, exclusive = false)
super(start_v, end_v, exclusive)
@step_size = step_size
end
def each (&block)
self.step(step_size).each(&block)
end
end
精彩评论