DLang对象与继承关系
不知道为什么,Bing 和 Google 上都没有 DLang 中类似 Java 的 instanceof 的用法说明。看了一天 Objects in D Prograssing Language 文档之后一无所获。最后我相信读代码应该能解决问题。当然,这个问题解决了,否则就没有这篇文章了。
首先我们依然需要知道一个概念:DLang 与任何面向对象语言一样,都有一个集中对象,就像 Java 与 Ruby 中是 Object,Kotlin 中是 Any。DLang 中使用的也是 Object(Class)。任何类与接口都是 Object 的派生类。而对象操作的集合则是一个单独的包,object
。object
不在 std 之中,而 object
默认被任何类继承,因此直接使用内部函数即可。
简单对比:is
与 object#typeid() -> TypeInfo
is
关键字用于比较对象身份。在 DLang 中,如果你想知道对象是否为 null,不可以直接使用比较运算 a == null
,而是 a is null
。 同样的,当我们想要检查身份时,也可以使用 is
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import std.stdio;
class A {}
class B: A {}
void main() {
A clazzA = new A();
B clazzB = new B();
auto infoA = typeid(clazzA);
auto infoB = typeid(clazzB);
writeln(a is a); // True, 因为对象都是 A 的实例
writeln(b is a); // False, a 是 A 的实例而 b 是 B 的实例,这与继承关系无关。
}
object
包下存在一种函数:typeid
。这个函数可以用于获取类与对象的基本数据,诸如名称等。自身的 toString()
函数指向类或接口的完全名称(从 module 到 ClassName,就像 Java 的完全名称是从包名到 ClassName).使用 typeid
可以直接比较对象类型而忽视细节。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import std.stdio;
class A {}
class B: A {}
void main() {
A clazzA = new A();
B clazzB = new B();
A clazzA2 = new A();
auto infoA = typeid(clazzA);
auto infoB = typeid(clazzB);
auto infoA2 = typeid(clazzA2);
writeln(infoA == infoA2); // True, 因为对象都是 A 的实例
writeln(infoA == clazzB); // False, 虽然 B 继承自 A,但是 A 与 B 的 TypeInfo 并不相同
}
对象一致性验证:toHash
与 equals
/opEquals
toHash
似乎没有什么可以讲的,因为还是我们熟悉的那些东西。
equals
是类对比独有函数,用于检查实例是否相同。
opEquals
是对象默认实现的函数,基于对象身份进行检查,默认使用 is
检查其身份。
继承关系:TypeInfo_Class#interfaces
与 TypeInfo_Class#isBaseOf(TypeInfo_Class) -> bool
最有意思的部分,这一部分貌似不在文档之中,但是它们就是我们想要的。或许是因为 Java 写多了导致的,在写 DLang 的面向对象的时候总是觉得自己在写反射。
小知识:ClassInfo
是 TypeInfo_Class
的别名(alias
)。
interfaces
是 ClassInfo
下的一个字段,类型是 Interface[]
。没错,这个字段装载着当前对象的类继承的全部接口。但是需要注意,这个仅限于当前类 直接继承 的接口。换言之,如果是继承了某个类或抽象类,父类携带的接口是不会被传入的。如果想要检查父类的接口,需要取得父类的 ClassInfo
。访问 ClassInfo
下的 base
字段即可。
虽然 DLang 没有 instanceof
这样的关键字,但是 ClassInfo
实现了 isBaseOf
函数。就当反射吧,它用于检查传入的类是否为当前类的子类。注意,传入的是类,是指 ClassInfo
,不可以传入对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import object;
import std.stdio;
interface FOO {
}
class A: FOO {
}
class B : A {
}
void main() {
auto a = new A();
auto b = new B();
writeln(instanceof(b, FOO.classinfo)); // True, 对象 b 的类数据 B 继承自接口 FOO。
writeln(instanceof(b, a.classinfo)); // True, 对象 b 的类数据 B 继承自对象 a 的类数据 A。
writeln(instanceof(a, b.A.classinfo)); // True,理所当然,b 的父类的类数据 A 与对象 a 的类数据 A 是一样的
writeln(instanceof(a, b.classinfo)); // False,关系颠倒
}
bool instanceof(Object obj, ClassInfo clazz) { // 检查函数在这里
return clazz.isBaseOf(obj.classinfo);
}