前言
Rust通过实现特性的特殊形式的类型,可以允许多态性的真正形式(True polymorphism)。这些被称为特性对象(trait objects)。在解释Rust如何使用trait对象实现多态性之前,首先需要理解分派(dispatch)的思想。
分派(dispatch)
分派是一个从面向对象编程(object-oriented programming,OOP)范式中产生的概念,在称为多态性的特性之一的上下文下产生。在OOP的上下文中,当API是泛型类型的或接受实现接口的参数时,它必须在传递给API的类型的实例上找出要调用的方法实现。在多态上下文中,这个方法解析的过程叫做分派,调用这个方法叫作分派。
在支持多态的主流语言中,分派主要有两种方式:
- 静态分派(Static dispatch):在编译时决定要调用的方法,被称为静态分派或早期绑定。该方法的签名用于决定要调用何种方法。在Rust中,泛型展示了这种形式的分派,因为即使泛型函数可以接受许多参数,在编译时也会使用该具体类型生成函数的专一副本(specialized copy)。
- 动态分派(Dynamic dispatch):在面向对象的语言中,有时直到运行时才能决定方法调用的类型。这是因为有些具体类型是隐藏的,只有接口方法可以调用该类型。在Java中,当一个函数有一个接口(interface)类型参数时,就是这种情况。这种场景只能通过动态分派来处理。在动态分派中,通过从虚函数表(vtable)中导航接口的实现列表并调用该方法来动态的确定方法类型。需要说明一点,虚函数表是指向每种类型的实现方法的函数指针的列表。显然,使用起来有一点开销,因为在方法调用中有额外的指针间接性(extra pointer indirection)。
特性对象(Trait objects)
到目前为止,主要看到的是在静态分派上下文中使用trait,在这里我们在泛型APIs中指定trait绑定。然而,也有另一种方式来创建多态APIs,我们可以将参数指定为实现trait的东西,而不是泛型或具体的类型。这种形式的类型被指定为实现trait API,称为特性对象(Trait objects)。特性对象类似于C+