impl Trait 是日常最常写的泛型语法糖。这篇验证它在参数位置和返回位置各自的真实含义、一个让人意外的限制(只能返回一种类型)、edition 2024 对生命周期捕获的改动,以及它不能做什么。
via_impl(调用 len_impl::<i32>)与 via_generic(调用 len_generic::<i32>)的汇编:
b __RINvCskmIYF9N4tvP_4u38b11len_genericlEB2_
别名行: `_via_impl = _via_generic`(两个包装函数被合并,说明它们调用的实例化函数一样) 源码:
1 | fn evens(limit: u32) -> impl Iterator<Item = u32> { (0..limit).filter(|n| n % 2 == 0) }
2 | fn adder(k: i32) -> impl Fn(i32) -> i32 { move |x| x + k }
3 | fn main() {
4 | println!("{:?}", evens(10).collect::<Vec<_>>());
5 | let f = adder(5); println!("adder(5)(3) = {}", f(3));
6 | println!("evens 返回的具体类型名:{}", std::any::type_name_of_val(&evens(1)));
7 | }
编译:成功
运行(退出码 0):
[0, 2, 4, 6, 8]
adder(5)(3) = 8
evens 返回的具体类型名:core::iter::adapters::filter::Filter<core::ops::range::Range<u32>, u38c::evens::{{closure}}>
源码:
1 | use std::fmt::Display;
2 | fn pick(flag: bool) -> impl Display { if flag { 1 } else { "one" } }
3 | fn main() { println!("{}", pick(true)); }
编译:失败
error[E0308]: `if` and `else` have incompatible types
--> <实验目录>/src/u38d.rs:2:60
|
2 | fn pick(flag: bool) -> impl Display { if flag { 1 } else { "one" } }
| - ^^^^^ expected integer, found `&str`
| |
| expected because of this
|
help: you could change the return type to be a boxed trait object
|
2 - fn pick(flag: bool) -> impl Display { if flag { 1 } else { "one" } }
2 + fn pick(flag: bool) -> Box<dyn Display> { if flag { 1 } else { "one" } }
|
help: if you change the return type to expect trait objects, box the returned expressions
|
2 | fn pick(flag: bool) -> impl Display { if flag { Box::new(1) } else { Box::new("one") } }
| +++++++++ + +++++++++ +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
源码:
1 | use std::fmt::Display;
2 | fn pick(flag: bool) -> Box<dyn Display> { if flag { Box::new(1) } else { Box::new("one") } }
3 | fn main() { println!("{} {}", pick(true), pick(false)); }
编译:成功
运行(退出码 0):
1 one需要运行时选择不同类型时用 trait 对象,见Trait Object 与动态分发。
--edition 2021:
源码:
1 | fn doubled(v: &Vec<u32>) -> impl Iterator<Item = u32> { v.iter().map(|x| x * 2) }
2 | fn main() { let v = vec![1, 2, 3]; println!("{:?}", doubled(&v).collect::<Vec<_>>()); }
编译:失败
error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
--> <实验目录>/src/u38f2021.rs:1:57
|
1 | fn doubled(v: &Vec<u32>) -> impl Iterator<Item = u32> { v.iter().map(|x| x * 2) }
| --------- ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | opaque type defined here
| hidden type `Map<std::slice::Iter<'_, u32>, {closure@<实验目录>/src/u38f2021.rs:1:70: 1:73}>` captures the anonymous lifetime defined here
|
help: add a `use<...>` bound to explicitly capture `'_`
|
1 | fn doubled(v: &Vec<u32>) -> impl Iterator<Item = u32> + use<'_> { v.iter().map(|x| x * 2) }
| +++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0700`.
--edition 2024:
编译:成功
运行(退出码 0):
[2, 4, 6]
源码:
1 | fn doubled<'a>(v: &'a Vec<u32>) -> impl Iterator<Item = u32> + 'a { v.iter().map(|x| x * 2) }
2 | fn main() { let v = vec![1, 2, 3]; println!("{:?}", doubled(&v).collect::<Vec<_>>()); }
编译:成功
运行(退出码 0):
[2, 4, 6]
(上面这段是 2021 里的写法:显式加 + 'a 就可以了)edition 2024 在 if let 临时值上的另一处变化见if let 与 let else。
源码:
1 | fn f(x: impl std::fmt::Display) -> String { x.to_string() }
2 | fn main() { println!("{}", f::<i32>(5)); }
编译:失败
error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
--> <实验目录>/src/u38g.rs:2:28
|
2 | fn main() { println!("{}", f::<i32>(5)); }
| ^------- help: remove the unnecessary generics
| |
| expected 0 generic arguments
|
note: function defined here, with 0 generic parameters
--> <实验目录>/src/u38g.rs:1:4
|
1 | fn f(x: impl std::fmt::Display) -> String { x.to_string() }
| ^
= note: `impl Trait` cannot be explicitly specified as a generic argument
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0107`.