将函数参数类型从
impl Trait
更改为泛型是否可能是重大更改? Rust Reference 指出:
注意:对于函数参数,泛型类型参数和
并不完全等价。对于诸如impl Trait
之类的泛型参数,调用者可以选择使用<T: Trait>
GenericArgs在调用站点显式指定T
的泛型参数,例如。如果foo::<usize>(1)
是任何函数参数的类型,则调用者在调用该函数时无法提供任何泛型参数。这包括返回类型的泛型参数或任何 const 泛型。impl Trait
因此,将函数签名从一个更改为另一个可能会对函数调用者构成重大更改。
但是考虑到,如果至少有一个
impl Trait
参数,那么调用者就无法命名任何泛型参数,这是否意味着将 impl Trait
更改为 <T: Trait>
只能让调用者命名泛型参数?由于泛型已经被推断出来,我们也不能破坏类型推断。
编辑:我假设每个
impl Trait
都更改为不同和独特泛型类型(与其他impl Trait
或以前的泛型不重叠)。违反这一点显然会被破坏,感谢@啊鹿Dizzyi 指出这一点。
我在这里列出了
impl Trait
更改为通用的案例列表(我认为是详尽的)。如果其中任何一个可能在下游断裂,请说明如何断裂。如果我错过了某些案例,请解释它是否损坏。
impl Trait
// before
fn foo(_: impl Trait) {}
// after
fn foo<T: Trait>(_: T) {}
impl Trait
,但只改变其中一些// before
fn foo(_: impl Trait1, _: impl Trait2, _: impl Trait3) {}
// after
fn foo<T1: Trait1, T2: Trait2>(_: T1, _: T2, _: impl Trait3) {}
impl Trait
,全部改变// before
fn foo(_: impl Trait1, _: impl Trait2, _: impl Trait3) {}
// after
fn foo<T1: Trait1, T2: Trait2, T3: Trait3>(_: T1, _: T2, _: T3) {}
impl Trait
,但至少保留一个// before
fn foo<T1: Trait1>(_: T1, _: impl Trait2, _: impl Trait3) {}
// after
fn foo<T1: Trait1, T2: Trait2>(_: T1, _: T2, _: impl Trait3) {}
impl Trait
s// before
fn foo<T1: Trait1>(_: T1, _: impl Trait2, _: impl Trait3) {}
// after
fn foo<T1: Trait1, T2: Trait2, T3: Trait3>(_: T1, _: T2, _: T3) {}
发生这种情况的一种情况是,当你想要函数接受两个都实现某些特征的参数时
Trait
,但你不关心两个参数是否是相同的类型。
自从定义泛型类型
T
以来,所有外观都绑定到同一类型。并且会导致错误,因此更改时需要小心。
trait Trait {}
fn foo_impl(_: impl Trait, _: impl Trait) {}
fn foo_generic<T: Trait>(_: T, _: T) {}
fn foo_generic_ok<T1: Trait, T2: Trait>(_: T1, _: T2) {}
impl Trait for i32 {}
impl Trait for f32 {}
fn main() {
foo_impl(1, 1.0);
foo_generic(1, 1.0); // <-- this will error
foo_generic_ok(1, 1.0);
}
error[E0308]: mismatched types
--> ****\src/main.rs:12:20
|
12 | foo_generic(1, 1.0);
| ----------- - ^^^ expected `i32`, found floating-point number
| | |
| | expected all arguments to be this `i32` type because they need to match the type of this parameter
| arguments to this function are incorrect
|
note: function defined here
--> ****\src/main.rs:4:4
|
4 | fn foo_generic<T: Trait>(_: T, _: T) {}
| ^^^^^^^^^^^ - ---- ---- this parameter needs to match the `i32` type of {unknown}
| | |
| | {unknown} needs to match the `i32` type of this parameter
| {unknown} and {unknown} all reference this parameter T
For more information about this error, try `rustc --explain E0308`.