我正在学习D编程语言,并尽可能地限制自己使用其中的SafeD子集。然而,我发现像writeln这样的I/O函数都是@system的。如何在SafeD中进行I/O操作呢?
我正在Fedora 19 x86-64上使用从Fedora软件包下载的LDC2。
我正在学习D编程语言,并尽可能地限制自己使用其中的SafeD子集。然而,我发现像writeln这样的I/O函数都是@system的。如何在SafeD中进行I/O操作呢?
我正在Fedora 19 x86-64上使用从Fedora软件包下载的LDC2。
你不能直接使用,或者至少不是直接使用。I/O 需要进行系统调用,这意味着需要使用 C 函数,而 C 函数不会被 @safe
修饰。由于 writeln
目前在内部调用的是 printf
,因此它肯定不会被标记为 @safe
,因为使用 printf
很容易出现不安全的情况(比如给它传递一个整数而不是字符串)。也许可以根据具体情况将 writeln
标记为 @trusted
,但我不知道涉及哪些方面。这取决于它的实现方式。
任何非平凡的 D 程序都预计会使用 @system
代码。关键是要隔离它。你的程序中大多数部分都应该是 @safe
的,但其中一部分将必须是 @system
的。然而,你只需要检查程序的一小部分是否存在内存安全问题。一旦你手动验证了调用 @system
函数的函数确实是内存安全的,就可以将其标记为 @trusted
,然后可以在 @safe
代码中使用它。
很不幸的是,由于在低级别的操作中使用了 @system
,因此 druntime 和 Phobos 中的某些核心部分很可能也会被标记为 @system
,并且其中并非所有部分都已经按照应该有的方式标记为 @trusted
(例如,std.array.appender
可能是 @system
,但实际上应该可以是 @trusted
- 我不确定它当前的状态如何;它可能取决于数组的元素类型)。因此,为了更好地支持 @safe
,一些标准库的改进可能需要进行(这正在进行中,但我不知道现在的情况),并且您可能需要现在在更多的地方使用 @trusted
,而不是未来。 writeln
未来可能成为 @safe
或 @trusted
,但如果您使用它的类型没有 @safe
或 @trusted
的 toString
函数,则无法实现。因此,无论如何实现,writeln
是否 @safe
取决于您使用它的方式,但即使对于内置类型,目前它也不是 @safe
或 @trusted
,所以现在您需要自己小心处理。
如果你真的想要,你可以创建一个writeln
的包装器,并将其标记为@trusted
,但你必须非常小心以确保代码实际上是内存安全的-仅仅创建一个模板化的包装器并将其标记为@trusted
是不够的,因为你无论传递什么类型,它都会被视为@safe
。所以,最好就是不包装它,然后如果你确定特定用法的writeln
是内存安全的,就将调用者标记为@trusted
。当然,这也突出了为什么像writeln
这样的函数当前在第一时间被标记为@system
的部分原因:往往很难编写@trusted
的模板化代码而不信任不应该被信任的东西(因为它取决于模板参数)。属性推断通常会解决问题,但如果模板化代码正在执行需要@trusted
的操作,则很难将代码的一部分标记为@trusted
并将其余部分留给推断,特别是如果模板参数与@system
相关的内容混合在一起。我预计我们最终将为所有标准库内容搞清楚这个问题。
我认为我们应该把writeln
及其他相关函数标记为@trusted
- 虽然它们使用了较低级别的原语,但它们足够检查以确保例如printf
没有收到混乱的参数。
@system
代码,但它是隔离的,并且通常只占很小一部分,因此自己验证其内存安全性是合理的。如果你完全没有@safe
,那么你就必须自己验证整个程序,这显然要困难得多。 - Jonathan M Davis@safe
功能(例如@safe
toString
),writeln
可能可以被安全地使用,但它不能简单地标记为@trusted
或@safe
,而且我不知道如何轻松地将适当的部分标记为@trusted
而不将不应该是@trusted
的部分标记为@trusted
。因此,根据实现方式,这可能会有点麻烦。不过,我相信我们可以做到。 - Jonathan M Davis