簡體   English   中英

如何動態導入 zig 模塊?

[英]How to import zig modules dynamically?

我正在使用 zig 0.7.0. 我正在嘗試從數組中導入 zig 源文件列表。 每個源文件都有一個我想調用的main function (其返回類型為!void )。 數組module_names在編譯時是已知的。

這是我試圖做的:

const std = @import("std");
const log = std.log;

const module_names = [_][]const u8{
    "01.zig", "02.zig", "03.zig", "04.zig", "05.zig",
};

pub fn main() void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    for (module_names) |module_name, i| {
        const module = @import(module_name); // this fails
        log.info("i {}", .{i});
        try module.main();
    }
}

即使數組在編譯時已知,@ @import(module_name)也會給我這個錯誤:

./src/main.zig:13:32: error: unable to evaluate constant expression
        const module = @import(module_name);
                               ^
./src/main.zig:13:24: note: referenced here
        const module = @import(module_name);

如果數組是動態生成的並且只在運行時知道,我可以理解錯誤,但這里的module_names數組在編譯時是已知的。 所以我有點迷茫...

或者,我還嘗試將整個main包裝在一個comptime塊中:

pub fn main() void {
    comptime {
        var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
        defer arena.deinit();

        for (module_names) |module_name, i| {
            const module = @import(module_name); // no errors here
            log.info("i {}", .{i});
            try module.main();
        }
    }
}

這里@import(module_name)沒有給我任何錯誤,但是log.info失敗並出現另一個錯誤:

/home/jack/.zig/lib/zig/std/mutex.zig:59:87: error: unable to evaluate constant expression
            if (@cmpxchgWeak(usize, &self.state, 0, MUTEX_LOCK, .Acquire, .Monotonic) != null)
                                                                                      ^
/home/jack/.zig/lib/zig/std/mutex.zig:65:35: note: called from here
            return self.tryAcquire() orelse {
                                  ^
/home/jack/.zig/lib/zig/std/log.zig:145:60: note: called from here
            const held = std.debug.getStderrMutex().acquire();
                                                           ^
/home/jack/.zig/lib/zig/std/log.zig:222:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/main.zig:26:21: note: called from here
            log.info("i {}", .{i});

這種動態導入可以在zig中實現嗎?

我認為您所追求的那種導入是可能的,我的理解是@import正在獲取一個zig源文件並將其轉換為結構類型。 它實際上似乎甚至可以在運行時完成(盡管不使用@import ,它需要一個comptime參數(這是您問題的重要部分)。

第一個示例失敗的原因是您傳遞的參數module_namecomptime ,您的for循環在程序運行之前不會執行。

您解決問題的直覺是正確的,在編譯時讓循環進行評估(特別是捕獲值和迭代器); 我認為你可以做兩件事來解決它。

像您所做的那樣將循環包裝在一個comptime塊中是可行的,但是您需要考慮在編譯時評估表達式的確切含義,以及它是否有意義。 我認為log的實現會阻止你在編譯時記錄,所以你需要在循環內收集你感興趣的值,並在comptime塊之外記錄它們。

您可以修復它的另一種方法是通過使用內聯 for展開循環來強制在編譯時評估循環的捕獲值:

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    inline for (module_names) |module_name, i| {
        const module = @import(module_name);
        log.info("i {}", .{i});
        try module.main();
    }
}

免責聲明:可能有更好的方法,我對語言比較陌生=D

Zig 0.8.0 開始@import @import 的操作數必須是字符串文字

Zig 編譯器想知道所有可能導入的文件,以便在您開始編譯過程時可以急切地找到它們並編譯它們。 通過使快速編譯器的存在成為可能,語言的設計受到了限制。

所以,我們能做些什么? 我認為這以等效的方式完成了任務:

const std = @import("std");
const log = std.log;

const modules = struct {
    pub const module_01 = @import("01.zig");
    pub const module_02 = @import("02.zig");
    pub const module_03 = @import("03.zig");
    pub const module_04 = @import("04.zig");
    pub const module_05 = @import("05.zig");
};

pub fn main() void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    inline for (@typeInfo(modules).Struct.decls) |decl, i| {
        const module = @field(modules, decl.name);
        log.info("i {d}", .{i});
        try module.main();
    }
}

這里的巧妙之處在於,事實上,編譯器能夠急切地獲取所有 5 個文件並啟動編譯過程,甚至在運行編譯時代碼以確定實際導入哪個文件之前。 雙贏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM