Rust的impl trait

fn的impl trait

作为参数

将trait作为参数传入:

1
2
3
4
5
6
7
8
9
10
11
12
#[allow(dead_code)]
fn b(a: impl Debug) {
println!("{:?}", a);
}

#[derive(Debug)]
struct Dummy;

#[test]
fn t1() {
b(Dummy);
}

上面的impl trait语法糖,脱糖后为:

1
2
3
4
5
6
7
fn b<impl std::fmt::Debug>(a: impl std::fmt::Debug) where
impl std::fmt::Debug: std::fmt::Debug {
{
::std::io::_print(::core::fmt::Arguments::new_v1(&["", "\n"],
&[::core::fmt::ArgumentV1::new_debug(&a)]));
};
}

如果这里将impl std::fmt::Debug 整体视为泛型T,我们转换后:

1
2
3
4
5
6
7
fn b<T>(a: T) where
T: std::fmt::Debug {
{
::std::io::_print(::core::fmt::Arguments::new_v1(&["", "\n"],
&[::core::fmt::ArgumentV1::new_debug(&a)]));
};
}

代码一下子清晰了。这里是编译期单态化(monomorphisation)实现的。编译器为每个类型创建一个function的拷贝

作为返回值

1
2
3
4
5
6
7
8
9
10
use std::fmt::Debug;

#[allow(dead_code)]
fn b() -> impl Debug {
1
}
#[test]
fn t1() {
dbg!(b());
}

返回类型中的impl trait实际上是existential type 存在的类型。

Existential type (存在类型)提供了一种在类型系统上抽象的方式,其中 existential type 这个名称源于 existential quantification (存在量词,数学符号∃)。

可以这样理解:某种形式的类型存在,但是在上下文中不知道它的具体类型。

trait 中作为参数

作为参数

1
2
3
trait B {
fn b(b: impl std::error::Error);
}

和前面fn参数同理

作为返回值

1
2
3
4

trait B {
fn b()->impl std::error::Error;
}

目前Rust不支持

1
2
3
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
--> src/lib.rs:2:13

这里用户要么使用泛型

1
2
3
trait B<T:std::error::Error> {
fn b()->T;
}

要么使用GAT

1
2
3
4
5
6
7
trait B {
type
RETURN: std::error::Error;
fn b()
-> Self::RETURN;
}

强制用户在实现此trait时必须指定类型T。不再能支持类型擦除。

  • 本文作者: fenix
  • 本文链接: https://fenix0.com/impl-trait/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC 许可协议。转载请注明出处!