存在类型(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 | fn foo(a: impl A) {...} |
这等价于
1 | fn foo<T: A>(a: T) {...} |
Rust以dyn A
表示任意类型:
1 | fn foo(a: &dyn A) {...} |
或
1 | fn foo(a: Box<dyn A>) {...} |
由于dyn A
的大小编译期未知, 所以需要使用引用, 或者使用指针例如Box
.
Swift存在类型(不透明类型)
设有Protocol A:
1 | protocol A {...} |
Swift以不透明类型表示存在类型, 与Rust非常相似:
1 | func foo(a: some A) {...} |
类似的, 这也等价于
1 | func foo<T: A>(a: T) {...} |
Swift以any A
表示任意类型:
1 | func foo(a: any A) {...} |
C++存在类型
C++中可以使用模板表示存在类型:
1 | template<typename T> |
也可以加入concept约束
1 | template<typename T> |
C++中任意类型和存在类型无法统一, 因为模板和concept只能用于静态约束, 任意类型需要动态约束, 可以用继承:
1 | class A {...}; |
其中引用也可以替换为指针或者智能指针.