我真的想使用D,因为它的语言结构所以很多我关心的东西比C ++更好,但几乎强制的GC(issue handled [sort of] here),稍微不那么强大的运算符重载(opDispatch
除外。opDispatch
性感),以下问题有点让我失望。
D中是否可以从定义中拆分方法声明?如果是这样,怎么样?如果没有,为什么?
'how'的激励示例:为了将实现隐藏在用户代码编写者的眼睛之外,提供二进制对象旁边的接口函数的小头文件,如C头和库一样。偏好:不取决于用户代码是否已经黑客攻击垃圾收集器,或者只是在没有druntime的情况下编译(such as this中找到here)。
答案 0 :(得分:4)
如果我像这样编写一个D文件:http://arsdnet.net/dcode/iface/test.d并使用dmd -c编译,你会看到它没有错误;这是一个有效的D文件。该语言允许您编写函数原型而无需实现。
.di文件就是这样,它只是有一个不同的文件名。
然后给出main:http://arsdnet.net/dcode/main.d如果你编译dmd main,当它看到“import iface.test;”时,会自动搜索iface / test.d,找到.d文件,或者.di if你重命名它但是同样的东西,并获得你的接口定义。
dmd main将因链接器错误而失败,因此我们需要实现它:http://arsdnet.net/dcode/impl.d注意:impl不会导入模块,因此它永远不会检查其他文件。保持.di和.d文件同步是一个棘手的部分,除非你自动生成接口文件,因为未定义的方法会给链接器错误,但方法的顺序很重要:它必须匹配,所以变量列表,如果有任何公共变量。否则,使用代码和实现代码将不同意类的布局。
同样,它不自动检查,实现文件根本不查看“header”文件,所以这与C ++的一个主要区别是你编写头文件一次,然后在使用程序和实现文件中使用它。
您会注意到实现文件也列出了类等。 D不支持void MyClass::add(int a) {}
语法C ++必须在类外编写方法。
据我所知,没有办法强制实现文件查找头文件,如果你把两个都放在命令行上,你会得到:“错误:来自文件iface / test.d的模块iface.test冲突使用文件impl.d中的另一个模块测试“
建议使用.di文件的方法是使用dmd -H自动生成它们。这将读取完整的实现文件并删除函数体,只留下定义。当他们说这是编译器的一个特性时,这部分可能是关键的一点 - .di文件是有效的标准D,但是通过编译器选项生成,不一定需要成为其他编译器的一部分。
答案 1 :(得分:3)
您可以使用extern
声明函数而不指定其实现,例如:
extern(D):
void foo(string name);
然后简单地提供一个目标文件/存档以及用于链接的实现。请注意,模块名称是函数的错误名称的一部分,因此头文件需要与编译模块相同的模块名称,或者您可以使用extern(C)
禁用修改(排除重载并使用C调用约定)。 / p>
答案 2 :(得分:3)
假设您正在开发一个名为 mylib 的库,它具有函数foo()和bar()。您的代码和库测试应用程序在开始时可能如下所示:
mylib.d - 界面文件
module mylib;
void foo();
void bar();
mylib_impl.d - 定义在这里
module mylib;
import std.stdio;
void foo() {
writeln("foo()");
}
void bar() {
writeln("bar()");
}
mylib_test.d - 测试应用
// To compile: dmd mylib_impl.d mylib_test.d
// NOTE: we do not compile the "interface" file mylib.d !!
module mylib_test;
import mylib;
int main() {
foo();
bar();
return 0;
}
现在应该不难理解我们的.di文件纯粹是为了方便和清晰。如果我们决定使用接口文件,我们会将mylib.d重命名为mylib.di,将mylib_impl.d重命名为mylib.d。 mylib_test.d将保持不变。