Zig 在没有分配器的情况下对运行时已知长度数组进行操作?

问题描述 投票:0回答:1

我认为这可能与冒泡排序本身无关,而更多地与我对 Zig“风格”的理解有关。

我的目标

我想在 Zig 中实现冒泡排序,以便它返回一个新数组。这种设置将使编写简单的单行测试变得更加容易。

问题

我不能这么做:

pub fn bubbleSort(arr: []const u8,) []const u8 {
    var arrSorted = [_]u8{0} ** arr.len;
    std.mem.copyForwards(u8, &arrSorted, arr);
    ...
}

因为 zig 会指出 arr.len 是一个未知的编译时属性

所以我最终这样做了:

const std = @import("std");

/// O(n^2)
pub fn bubbleSort(arr: []const u8, comptime len: u8) []const u8 {
    var arrSorted = [_]u8{0} ** len;
    std.mem.copyForwards(u8, &arrSorted, arr);

    for (0..arrSorted.len) |i| {
        for (0..arrSorted.len - i - 1) |j| {
            if (arrSorted[j] > arrSorted[j + 1]) {
                const tmp = arrSorted[j];
                arrSorted[j] = arrSorted[j + 1];
                arrSorted[j + 1] = tmp;
            }
        }
    }

    return &arrSorted;
}

test "bubble sort" {
    try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 4, 7, 8, 9, 102 }, bubbleSort(&[_]u8{ 1, 102, 7, 4, 8, 9 }, 6));
    try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 4, 7, 8, 9, 102 }, bubbleSort(&[_]u8{ 102, 7, 4, 1, 8, 9 }, 6));
    try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 4, 7, 8, 9, 102 }, bubbleSort(&[_]u8{ 1, 102, 7, 4, 9, 8 }, 6));
    try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 4, 7, 8, 9, 102 }, bubbleSort(&[_]u8{ 9, 1, 102, 7, 4, 8 }, 6));
    try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 4, 7, 8, 9, 102 }, bubbleSort(&[_]u8{ 1, 7, 4, 8, 9, 102 }, 6));
}

这里,我将数组的长度作为参数传递。通过直接在“纯文本”中指定该值,它在编译时就已知,因此所有这些都有效。

我的问题

我知道我可以将分配器传递给 bubbleSort 函数,让它为我的数组分配内存,然后推迟在调用代码块中释放该内存。这对于我想要实现的目标来说是正确的方法吗?

还有其他更简单、更快或更优雅的方法吗?

感谢您的阅读,如果标题或帖子不完美,我们深感抱歉——我想不出更好的方法来解释它。

我尝试从函数返回一个新数组,而不需要分配器或 comptime 已知属性,但失败了。

sorting memory zig
1个回答
0
投票

公平地说,我不确定您在测试中拥有漂亮俏皮话的目标是否可以实现。以下是标准库中排序函数的测试方式:std.sort.zig:225
最好的选择是定义一个辅助函数来完成所有繁重的工作,并且您可以多次调用它。

Zig 有以下内存分配选项:

  • 接受分配器。
  • 接受目标内存。
  • 在线更新结果。这通常是最好的,因为它隔离了操作。因此您可以随意使用您喜欢的任何内存分配策略。
  • 使用全局分配器。

您可能会注意到您的方法:

var arrSorted = [_]u8{0} ** len;
// ...
return &arrSorted;

未在可用选项中列出。这是因为这样做是违法的。这是新手常犯的错误,特别是如果他们有 GC 语言经验的话。内存仅在函数执行时由该函数拥有,一旦退出,该内存将被其他函数重用。根据程序的执行,这可能会产生正确的结果,也可能会产生完全无意义的结果。

© www.soinside.com 2019 - 2024. All rights reserved.