我今年一直在做《Advent of Code》,以学习 Zig,我在第 5 天发现了一些让我真正困惑的东西。那么:我猜,2022 年代码降临第 5 天会有轻微剧透吗?
我决定在第 5 天将我的解决方案实现为 U8 的 ArrayList 的 ArrayList,最终效果良好。我的完整解决方案文件是here https://github.com/daogilvie/aoc2022/blob/main/src/day5.zig(可能非常不习惯 Zig,但我们都必须从某个地方开始)。
作为我的解决方案的一部分,我有一个函数,我称之为 moveCrates,它位于一个包装数组列表的数组列表的结构上。
结构声明的相关部分如下所示:
const BunchOfStacks = struct {
stacks: ArrayList(ArrayList(u8)),
...
这个函数是here https://github.com/daogilvie/aoc2022/blob/d82304dbf855eb6f877e7d37e3b666206fd169f1/src/day5.zig#L36-L41,看起来像这样:
fn moveCrates(self: *BunchOfStacks, amount: usize, source: usize, dest: usize) !void {
const source_height = self.stacks.items[source - 1].items.len;
const crate_slice = self.stacks.items[source - 1].items[(source_height - amount)..];
try self.stacks.items[dest - 1].appendSlice(crate_slice);
self.stacks.items[source - 1].shrinkRetainingCapacity(source_height - amount);
}
您可以注意到,我通过非常详细的参考文献引用了源列表 3 次self.stacks.items[source - 1]
。这不是我第一次编写这个函数的方式。我首先是这样写的:
fn moveCrates(self: *BunchOfStacks, amount: usize, source: usize, dest: usize) !void {
var source_list: ArrayList(u8) = self.stacks.items[source - 1];
const source_height = source_list.items.len;
const crate_slice = source_list.items[(source_height - amount)..];
try self.stacks.items[dest - 1].appendSlice(crate_slice);
source_list.shrinkRetainingCapacity(source_height - amount);
}
但是第二种形式,为了方便起见,我创建了一个局部变量,但没有给出正确的结果!它编译得很好,但似乎总是指向source_list
到同一个内部ArrayList(u8)
(以它第一个选择的为准)无论其值是多少source
是。这意味着测试示例产生不正确的输出。
该函数在循环内调用,如下所示:
while (instructions.next()) |_| {
// First part is the verb, this is always "move" so skip it
// Get the amount next
const amount: usize = try std.fmt.parseInt(usize, instructions.next().?, 10);
// now skip _from_
_ = instructions.next();
// Now get source
const source: usize = try std.fmt.parseInt(usize, instructions.next().?, 10);
// Now skip _to_
_ = instructions.next();
// Now get dest
const dest: usize = try std.fmt.parseInt(usize, instructions.next().?, 10);
var crates_moved: usize = 0;
while (crates_moved < amount) : (crates_moved += 1) {
try stacks_part1.moveCrates(1, source, dest);
}
try stacks_part2.moveCrates(amount, source, dest);
}
最终,如您所见,我刚刚避免在函数中进行变量赋值,并且这通过了测试(和难题)。
我已经检查了 zig 存储库中可能相关的问题,但找不到任何明显的东西(使用的搜索是this https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+assignment+loop)。我查看了 StackOverflow,发现这个问题 https://stackoverflow.com/questions/66630797/how-to-create-2d-arrays-of-containers-in-zig,这确实与我的问题有一些相似之处(指针在 while 循环中似乎有点混乱),但它并不相同。
我已经搜索了有关循环和赋值的 Zig 文档,site https://ziglang.org/documentation/master/,但没有看到任何专门指出此行为的内容。
我假设我要么完全误解了某些东西(或者错过了一些没有很好记录的东西),要么这是一个错误——毕竟,该语言正在大量活跃的开发中。
我期望像我执行的那样的作业应该按预期工作——作为一个简单的速记,以避免必须写出重复的内容self.stacks.items[source - 1]
,所以我希望这是我做错的事情。 Zig 版本是v0.11.0-dev.537+36da3000c