I’m trying to understand how to correctly manage resources when using futures. The following example does not compile:
const std = @import("std");
const Io = std.Io;
const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList;
pub fn main(init: std.process.Init) !void {
const gpa = init.gpa;
const io = init.io;
var numbers_future = io.async(createNumbers, .{gpa});
defer if (numbers_future.cancel(io)) |numbers| numbers.deinit(gpa) else |_| {};
const numbers = try numbers_future.await(io);
for (numbers.items) |number| {
std.debug.print("Number: {}\n", .{number});
}
}
fn createNumbers(gpa: Allocator) !std.ArrayList(i32) {
var numbers: std.ArrayList(i32) = .empty;
errdefer numbers.deinit(gpa);
try numbers.append(gpa, 1);
try numbers.append(gpa, 2);
return numbers;
}
src/main.zig:11:59: error: expected type '*T', found '*const T'
defer if (numbers_future.cancel(io)) |numbers| numbers.deinit(gpa) else |_| {};
~~~~~~~^~~~~~~
src/main.zig:11:59: note: T = array_list.Aligned(i32,null)
src/main.zig:11:59: note: cast discards const qualifier
If I understand the Zig 0.16.0 changelog correctly this is the recommended pattern to handle resources.
Use this pattern to avoid resource leaks and handle Cancelation gracefully:
But it fails because the std.ArrayList.deinit function takes the ArrayList by a mutable pointer which seems to be very common in Zig for deinit functions.
Am I missing something? How to correctly release resources in this case?