ranges/ranges.go
func (r *InclusiveRange) End() int {
	if r.isEndCached {
		return r.cachedEnd
	}

	r.isEndCached = true

	// If we aren't stepping, or we don't have
	// a full range, then just use the end value
	if r.step == 1 || r.step == -1 || r.start == r.end {
		r.cachedEnd = r.end
		return r.cachedEnd
	}

	// If the step is in the wrong direction,
	// compared to the range direction, then
	// just use the start as the end.
	if (r.end < r.start) && r.step < (r.end-r.start) {
		r.cachedEnd = r.start
		return r.cachedEnd

	} else if (r.end > r.start) && r.step > (r.end-r.start) {
		r.cachedEnd = r.start
		return r.cachedEnd
	}

	// Calculate the end, taking into account the stepping
	r.cachedEnd = r.closestInRange(r.end, r.start, r.end, r.step)
	return r.cachedEnd
}
func (r *InclusiveRange) End() int {
	if r.isEndCached {
		return r.cachedEnd
	}

	r.isEndCached = true

	// If we aren't stepping, or we don't have
	// a full range, then just use the end value
	if r.step == 1 || r.step == -1 || r.start == r.end {
		r.cachedEnd = r.end
		return r.cachedEnd
	}

	// If the step is in the wrong direction,
	// compared to the range direction, then
	// just use the start as the end.
	if (r.end < r.start) && r.step < (r.end-r.start) {
		r.cachedEnd = r.start
		return r.cachedEnd

	} else if (r.end > r.start) && r.step > (r.end-r.start) {
		r.cachedEnd = r.start
		return r.cachedEnd
	}

	// Calculate the end, taking into account the stepping
	r.cachedEnd = r.closestInRange(r.end, r.start, r.end, r.step)
	return r.cachedEnd
}
// End returns the end of the range. This value may
// be different from the end value given when the
// range was first initialized, since it takes into
// account the stepping value. The end value may be
// shifted to the closest valid value within the
// stepped range.