I'm currently trying to solve some leetcode problems in Zig, and I'm doing the two sum problem. Here's what the entirety of my code looks like:
const std = @import("std");
const allocator = std.heap.page_allocator;
fn two_sum(nums: []i32, target: i32) []i32{
var map = std.AutoArrayHashMap(i32, i32).init(allocator);
defer map.deinit();
var res = [2]i32{-1, -1};
for (nums, 0..) |n, i| { // n is the number; i is the index
if (map.get(target - n)) |v| {
res[0] = v;
res[1] = @as(i32, i);
return &res;
}
try map.put(n, @as(i32, i));
}
return &res;
}
pub fn main() !void {
var arr = [_]i32{1, 5, 8, 9, 6};
var x = two_sum(&arr, 9);
for (x) |n| {
std.debug.print("{d}", .{n});
}
}
However, when I run the code, I get this error:
error: expected type 'i32', found 'usize'
res[1] = @as(i32, i);
^
Why is zig interpreting 1 as a usize
and not an i32
? And what can be done to fix this?
I tried using an explicit type cast: res[@as(i32, 1)] = @as(i32, i);
However, that didn't work either.
The immediate problem is that i
has type usize
, and you can't cast from usize
to i32
using @as
since an i32
can't hold all of the values that a usize
might hold. Instead, use @intCast
which is specifically for these situations when you know that the cast is safe. There are two such casts using @as
that need to be changed to @intCast
.
The two_sum
function needs to return an error union since it is using try
around the call to map.put
. And since two_sum
needs to return an error union, calls to two_sum
need to handle that, e.g., by using try
.
Finally, res
is a local variable, and you shouldn't return a pointer to a local variable; the storage associated with local variables is not valid after control leaves the local scope, and attempting to access such invalid memory leads to undefined behavior. Instead of returning a pointer, just return (a copy of) the array.
Here is a version of OP posted code with the above changes.
const std = @import("std");
const allocator = std.heap.page_allocator;
fn two_sum(nums: []i32, target: i32) ![2]i32 { // return error union
var map = std.AutoArrayHashMap(i32, i32).init(allocator);
defer map.deinit();
var res = [2]i32{ -1, -1 };
for (nums, 0..) |n, i| {
if (map.get(target - n)) |v| {
res[0] = v;
res[1] = @intCast(i32, i); // use `@intCast` instead of `@as`
return res; // just return the array
}
try map.put(n, @intCast(i32, i)); // use `@intCast` instead of `@as`
}
return res; // just return the array
}
pub fn main() !void {
var arr = [_]i32{1, 5, 8, 9, 6};
var x = try two_sum(&arr, 9); // `two_sum` returns an error union
for (x) |n| {
std.debug.print("{d}", .{n});
}
std.debug.print("\n", .{});
}