我最近开始学习 Zig。作为一个小项目,我想实现一个用于编写随机测试的小型 QuickCheck [1] 样式帮助程序库。
但是,我不知道如何编写通用方法来调用具有任意数量参数的函数。
这是一个简化版本,可以使用两个参数测试函数:
const std = @import("std");
const Prng = std.rand.DefaultPrng;
const Random = std.rand.Random;
const expect = std.testing.expect;
// the thing we want to test
fn some_property(a: u64, b: u64) !void {
var tmp: u64 = undefined;
var c1 = @addWithOverflow(u64, a, b, &tmp);
var c2 = @addWithOverflow(u64, a, b, &tmp);
expect(c1 == c2);
}
// helper for generating random arguments for the function under test
fn gen(comptime T: ?type, rnd: Random) (T orelse undefined) {
switch (T orelse undefined) {
u64 => return rnd.int(u64),
f64 => return rnd.float(f64),
else => @compileError("unsupported type"),
}
}
/// tests if 'property' holds.
fn for_all(property: anytype) !void {
var rnd = Prng.init(0);
const arg_types = @typeInfo(@TypeOf(property)).Fn.args;
var i: usize = 0;
while (i < 100) {
var a = gen(arg_types[0].arg_type, rnd.random());
var b = gen(arg_types[1].arg_type, rnd.random());
var args = .{a, b}; // <-- how do I build args for functions with any number of arguments?
try @call(.{}, property, args);
i += 1;
}
}
test "test" {
try for_all(some_property);
}
我尝试了一些不同的方法,但我不知道如何让上述代码适用于具有任意数量参数的函数。
我尝试过的事情:
- 制作
args
一个数组并用inline for
循环填充它。不起作用,因为[]anytype
不是有效类型。 - 使用一点 comptime 魔法来构建一个结构类型,其字段包含
@call
. 这在编译器中遇到了一个 TODO:error: TODO: struct args
. - 编写返回适当参数元组调用的通用函数。我真的不喜欢这个,因为你需要一个函数来支持你想要支持的每一个 arity。但它似乎无论如何都不起作用,因为
antype
它不是有效的返回类型。
我在 Zig 0.9.1。
任何见解将不胜感激。