文章

DLang对象与继承关系

DLang对象与继承关系

不知道为什么,Bing 和 Google 上都没有 DLang 中类似 Java 的 instanceof 的用法说明。看了一天 Objects in D Prograssing Language 文档之后一无所获。最后我相信读代码应该能解决问题。当然,这个问题解决了,否则就没有这篇文章了。

首先我们依然需要知道一个概念:DLang 与任何面向对象语言一样,都有一个集中对象,就像 Java 与 Ruby 中是 Object,Kotlin 中是 Any。DLang 中使用的也是 Object(Class)。任何类与接口都是 Object 的派生类。而对象操作的集合则是一个单独的包,objectobject 不在 std 之中,而 object 默认被任何类继承,因此直接使用内部函数即可。

简单对比:isobject#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 并不相同
}

对象一致性验证:toHashequals/opEquals

toHash 似乎没有什么可以讲的,因为还是我们熟悉的那些东西。

equals 是类对比独有函数,用于检查实例是否相同。

opEquals 是对象默认实现的函数,基于对象身份进行检查,默认使用 is 检查其身份。

继承关系:TypeInfo_Class#interfacesTypeInfo_Class#isBaseOf(TypeInfo_Class) -> bool

最有意思的部分,这一部分貌似不在文档之中,但是它们就是我们想要的。或许是因为 Java 写多了导致的,在写 DLang 的面向对象的时候总是觉得自己在写反射。

小知识:ClassInfoTypeInfo_Class 的别名(alias)。

interfacesClassInfo 下的一个字段,类型是 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);
}
本文章以 CC BY 4.0 授權