简体   繁体   English

当执行简单的变量赋值更改 function 行为时,我是否在 Zig 中使用了错误的 ArrayLists?

[英]Am I using ArrayLists wrong in Zig when performing simple variable assignment changes function behaviour?

I have been doing Advent of Code this year, to learn Zig, and I discovered something during Day 5 that really confused me.今年我一直在学习 Advent of Code,学习 Zig,我在第 5 天发现了一些让我很困惑的东西。 So: mild spoilers for Day 5 of Advent of Code 2022, I guess?所以:我猜是关于代码 2022 的第 5 天的温和破坏者?

I decided to implement my solution to Day 5 as an ArrayList of ArrayLists of U8s, which has ended up working well.我决定将第 5 天的解决方案实施为 U8 的 ArrayLists 的 ArrayList,它最终运行良好。 My full solution file is here (probably terribly un-idiomatic Zig, but we all have to start somewhere).我的完整解决方案文件在这里(可能非常不合惯用 Zig,但我们都必须从某个地方开始)。

As part of my solution, I have a function, which I call moveCrates, on a struct which wraps my arraylist of arraylists.作为我的解决方案的一部分,我有一个 function,我称之为 moveCrates,在一个结构上,它包装了我的 arraylist 数组列表。

The relevant part of the struct declaration looks as so:结构声明的相关部分如下所示:

const BunchOfStacks = struct {
    stacks: ArrayList(ArrayList(u8)),
    ...

This function is here , and looks like this:这个 function 在这里,看起来像这样:

    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);
    }

You can note that I refer 3 times to the source list by the very verbose reference self.stacks.items[source - 1] .您可以注意到,我通过非常冗长的引用self.stacks.items[source - 1]引用了 3 次源列表。 This is not how I first wrote this function. I first wrote it like below:这不是我最初写这个 function 的方式。我最初是这样写的:

    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);
    }

But this second form, where I make a local variable for my convenience, DOES NOT GIVE THE CORRECT RESULTS, It compiles fine, but seems to always point source_list to the same internal ArrayList(u8) (whichever one it first picks) regardless of what the value of source is.但是这第二种形式,为了方便我创建了一个局部变量,没有给出正确的结果,它编译得很好,但似乎总是将source_list指向同一个内部ArrayList(u8) (无论它首先选择哪个),不管是什么source的价值是。 This means that the test example produces incorrect output.这意味着测试示例产生了错误的 output。

This function is called within a loop, like so:这个 function 在循环中调用,如下所示:

    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);
    }

Ultimately, as you can see, I have just avoided making variable assignments in the function and this passes the test (and the puzzle).最终,如您所见,我刚刚避免在 function 中进行变量赋值,这通过了测试(和谜题)。

I have checked for issues in the zig repo that might be related, and cannot find anything immediately obvious (search used is this ).我已经检查了 zig 存储库中可能相关的问题,但无法立即找到任何明显的问题(使用的搜索是this )。 I've looked on StackOverflow, and found this question , which does have some similarity to my issue (pointers seem a bit whack in while loops), but it's not the same.我查看了 StackOverflow,发现了这个问题,它确实与我的问题有一些相似之处(指针在 while 循环中似乎有点不正常),但并不相同。

I've scoured the zig documentation on loops and assignment, on the site , but don't see anything calling out this behaviour specifically.我已经在网站上搜索了关于循环和赋值的 zig 文档,但没有看到任何具体指出此行为的内容。 I'm assuming I've either completely misunderstood something (or missed something that isn't well documented), or this is a bug — the language is under heavy active dev, after all.我假设我要么完全误解了某些东西(或者错过了一些没有很好记录的东西),要么这是一个错误——毕竟该语言处于大量活跃的开发之下。

I'm expecting that an assignment like I perform should work as expected — being a simple shorthand to avoid having to write out the repeated self.stacks.items[source - 1] , so I'm hopeful that this is something that I'm just doing wrong.我期待像我执行的作业应该按预期工作——作为一个简单的速记,以避免必须写出重复的self.stacks.items[source - 1] ,所以我希望这是我的东西我只是做错了。 Zig version is v0.11.0-dev.537+36da3000c Zig 版本是v0.11.0-dev.537+36da3000c

An array list stores items as a slice (a pointer to the first item plus length).数组列表将items存储为切片(指向第一项加上长度的指针)。 When you do当你做

var source_list: ArrayList(u8) = self.stacks.items[source - 1];

you make a shallow copy of the array list.您制作了数组列表的浅表副本。 You might be confused by your knowledge of some higher-level languages where this would've copied a reference to an object of the array list, but in Zig this isn't the case.您可能会对某些高级语言的知识感到困惑,在这些语言中,这会复制对数组列表的 object 的引用,但在 Zig 中情况并非如此。 In Zig everything is a "value object".在 Zig 中,一切都是“值对象”。

When you call shrinkRetainingCapacity it changes the length property of the items slice, but the changes are done to the local copy of the array list.当您调用shrinkRetainingCapacity时,它会更改items切片的长度属性,但更改是对数组列表的本地副本完成的。 The "real" array list, that is stored in another array list, remain unaffected.存储在另一个数组列表中的“真实”数组列表不受影响。

TL;DR You need to use a pointer : TL;DR 你需要使用一个指针

var source_list: *ArrayList(u8) = &self.stacks.items[source - 1];

This fixes the failing test.这修复了失败的测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM