在Zig中使用ArrayList时,变量赋值为何会改变函数行为?
为何Zig中ArrayList赋值给局部变量后操作异常?
问题出在Zig的类型语义上:ArrayList(T)是值类型,不是引用类型。当你把self.stacks.items[source - 1]赋值给局部变量source_list时,你做的是完整的结构体拷贝,而非创建指向原ArrayList的引用。
错误代码的问题分析
看你最初的实现:
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的副本:它拷贝了原ArrayList的allocator、items切片和capacity字段。- 你调用
source_list.shrinkRetainingCapacity(...)时,只会修改这个栈上副本的items切片长度,完全不会影响self.stacks里的原ArrayList。 - 虽然
crate_slice指向的是原底层数组的内存(因为切片是指针+长度),但原栈的长度没有被正确缩短,后续循环调用时,原栈的状态始终是错误的,看起来就像source_list始终指向同一个ArrayList。
正确代码的逻辑
第二段代码直接操作self.stacks.items[source - 1]:
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); }
所有操作都直接作用于self.stacks中的原ArrayList实例,修改的是它的实际状态,因此行为符合预期。
优化写法(兼顾简洁与正确性)
如果想用局部变量简化代码,应该使用指针指向原ArrayList,而不是赋值拷贝:
fn moveCrates(self: *BunchOfStacks, amount: usize, source: usize, dest: usize) !void { var source_list = &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的指针,所有对它的操作都会直接修改self.stacks中的实例,既避免了重复写长表达式,又保证了逻辑正确。
内容的提问来源于stack exchange,提问作者Drum
相关产品推荐
相关产品推荐

