If we're going for readability instead of trying to stick to the case presented above, I'd go with:
for i.HasNext() {
current := i.GetNext()
...
}
And just mutate the internal state of the struct. Probably throw it behind some sort of interface like:
type Iterator[T any] interface { // feel free to strip out the generic
HasNext() bool // if you really only have one type
GetNext() T // you do this with
}
I think this still loses to ranging over a function, but I still think it should be compared to what you can do with the current language as opposed to what was originally posted.