我正在尝试生成一个结构,该结构包含对 stdin/stdout/stderr 的每个读者和写者的引用
然而,我却无法声明适当的类型。我最简单的代码是:
const std = @import("std");
const IoTrio = struct {
in: std.io.GenericReader,
out: std.io.GenericWriter,
err: std.io.GenericWriter,
};
pub fn giveIo() !IoTrio {
const stdout = std.io.getStdOut().writer();
var stdin_bo = std.io.bufferedReader(std.io.getStdIn().reader());
const stdin = stdin_bo.reader();
const stderr = std.debug;
@compileLog(@TypeOf(stdin ));
@compileLog(@TypeOf(stdout));
@compileLog(@TypeOf(stderr));
return IoTrio{
.in = stdin,
.out = stdout,
.err = std.debug,
};
}
pub fn main() !void {
_ = giveIo();
}
该结构编译失败:
Produces error:
types.zig:5:15: error: expected type 'type', found 'fn (comptime type, comptime type, comptime anytype) type'
in: std.io.GenericReader,
~~~~~~^~~~~~~~~~~~~~
我看了这个答案,但不幸的是,它并没有真正的帮助——正如答案的作者所指出的那样,输出是复杂的,不容易理解——讨论到此结束。
事实上,输出结果相当令人困惑:
@as(type, io.GenericReader(*io.buffered_reader.BufferedReader(4096,io.GenericReader(fs.File,error{AccessDenied,Unexpected,InputOutput,BrokenPipe,SystemResources,OperationAborted,WouldBlock,ConnectionResetByPeer,IsDir,ConnectionTimedOut,NotOpenForReading,SocketNotConnected},(function 'read'))),error{AccessDenied,Unexpected,InputOutput,BrokenPipe,SystemResources,OperationAborted,WouldBlock,ConnectionResetByPeer,IsDir,ConnectionTimedOut,NotOpenForReading,SocketNotConnected},(function 'read')))
@as(type, io.GenericWriter(fs.File,error{AccessDenied,Unexpected,DiskQuota,FileTooBig,InputOutput,NoSpaceLeft,DeviceBusy,InvalidArgument,BrokenPipe,SystemResources,OperationAborted,NotOpenForWriting,LockViolation,WouldBlock,ConnectionResetByPeer},(function 'write')))
@as(type, type)
这似乎暗示每个都是一个函数?但我无法将这些值插入到我的结构声明中,也不明白这是什么意思,让我猜测一些更合理的内容。
我如何读取这些输出来得出我的结构所需的类型符号?
将读者和作者存储在结构中很困难。
第一个问题是该函数的
GenericWriter
名称不太恰当。该函数通过写入函数和写入函数实现的一些上下文来构建通用写入器。请注意,即使您的代码已编译,您仍会遇到释放后使用问题。缓冲读取器会在堆栈上创建一个缓冲区,但此堆栈会在函数退出时失效,从而使您拥有来自无效内存的读取器。
那么这个缓冲区应该放在哪里呢?它不能在你的结构体中,因为所有通用读取器都必须有足够的空间来存储程序中使用的最大缓冲区。它也不能存在于堆上,因为 Zig 不会隐式分配。你还必须释放它,但你没有这样做。
如果您不想依赖特定的读取器/写入器实现,则可以很容易地在主函数中创建所需的所有读取器和写入器,然后将它们作为“writer:anytype”参数传递给其他函数,而不是像在这里一样传递它们。
如果你确实需要将它们存储在结构体中,那么可以使用
AnyWriter
和AnyReader
。但正确使用这些很难,因为你必须自己管理它们的状态。以下是你可以这样做的示例:此代码创建读取器和写入器,在堆上分配它们的状态,并在调用 deinit 时清理它们。如果您在堆栈上创建它们并将其生命周期绑定到某个本地范围,则所有这些都会自动发生: