0%

存在类型 (existential type)

存在类型(existential type), 表示某个类型存在, 设Trait A, 则some A表示存在某个类型符合A特征;
与存在类型相对应的为任意类型, any A表示负责A特征的任意类型.

设B <: A, C <: A, 则List[some A]可以是List[B]或List[C], List中元素皆为同一类型; 与之对应, List[any A]则表示该List可以存储B或C类型, List中元素不需要为同一类型.

通常, 存在类型可以编译期确定, 而任意类型需要运行期确定, 所以存在类型可以静态派发, 任意类型一般需要动态派发, 因此使用存在类型代替任意类型可以提高效率.

Rust存在类型

设有Trait A:

1
trait A {...}

Rust以impl A表示存在类型:

1
2
3
fn foo(a: impl A) {...}

fn bar(a: Vec<impl A>) {...}

这等价于

1
2
3
fn foo<T: A>(a: T) {...}

fn bar<T: A>(a: Vec<T>) {...}

Rust以dyn A表示任意类型:

1
2
3
fn foo(a: &dyn A) {...}

fn bar(a: Vec<&dyn A>) {...}

1
2
3
fn foo(a: Box<dyn A>) {...}

fn bar(a: Vec<Box<dyn A>>) {...}

由于dyn A的大小编译期未知, 所以需要使用引用, 或者使用指针例如Box.

Swift存在类型(不透明类型)

设有Protocol A:

1
protocol A {...}

Swift以不透明类型表示存在类型, 与Rust非常相似:

1
2
3
func foo(a: some A) {...}

func bar(a: Array<some A>) {...}

类似的, 这也等价于

1
2
3
func foo<T: A>(a: T) {...}

func bar<T: A>(a: Array<T>) {...}

Swift以any A表示任意类型:

1
2
3
func foo(a: any A) {...}

func bar(a: Array<any A>) {...}

C++存在类型

C++中可以使用模板表示存在类型:

1
2
3
4
5
template<typename T>
auto foo(T) -> void {...}

template<typename T>
auto bar(std::span<T>) -> void {...}

也可以加入concept约束

1
2
3
4
5
6
7
8
template<typename T>
concept A = requires(T a) {...};

template<A T>
auto foo(T) -> void {...}

template<A T>
auto bar(std::span<T>) -> void {...}

C++中任意类型和存在类型无法统一, 因为模板和concept只能用于静态约束, 任意类型需要动态约束, 可以用继承:

1
2
3
4
5
class A {...};

auto foo(A&) -> void {...} // 可以传入任意A的子类型

auto bar(std::span<A&>) -> void {...} // span中可以存储任意A的子类型引用

其中引用也可以替换为指针或者智能指针.

参考链接

https://en.wikipedia.org/wiki/Type_system#Existential_types