I also think that it’s annoying sometimes that you can’t do that. And sometimes it’s really annoying to work around it because it can destroy code locality.
I assume that the function returns a constant because you simplified your example to make it easier for us. Anyway, this should work:
const std = @import("std");
pub fn main() !void {
var it = iterator();
while (it.next()) |n| std.debug.print("{}\n", .{n});
}
fn Iterator() type {
return struct {
n: usize = 0,
pub fn next(it: *@This()) ?usize {
if (it.n >= 5) return null;
defer it.n += 1;
return it.n;
}
};
}
fn iterator() Iterator() {
return .{};
}
This can of course be extended to this:
const std = @import("std");
pub fn main() !void {
var it = iterator(@as(i32, 3));
while (it.next()) |n| std.debug.print("{}\n", .{n});
}
fn Iterator(T: type) type {
return struct {
n: T = 0,
pub fn next(it: *@This()) ?T {
if (it.n >= 5) return null;
defer it.n += 1;
return it.n;
}
};
}
fn iterator(start: anytype) Iterator(@TypeOf(start)) {
return .{.n = start};
}