将函数参数中的 impl Trait 更改为泛型是否会是重大更改?

问题描述 投票:0回答:1

将函数参数类型从

impl Trait
更改为泛型是否可能是重大更改? Rust Reference 指出:

注意:对于函数参数,泛型类型参数和

impl Trait
并不完全等价。对于诸如
<T: Trait>
之类的泛型参数,调用者可以选择使用
GenericArgs
在调用站点显式指定 T 的泛型参数,例如
foo::<usize>(1)
。如果
impl Trait
是任何函数参数的类型,则调用者在调用该函数时无法提供任何泛型参数。这包括返回类型的泛型参数或任何 const 泛型。

因此,将函数签名从一个更改为另一个可能会对函数调用者构成重大更改。

但是考虑到,如果至少有一个

impl Trait
参数,那么调用者就无法命名任何泛型参数,这是否意味着将
impl Trait
更改为
<T: Trait>
只能让调用者命名泛型参数?由于泛型已经被推断出来,我们也不能破坏类型推断。

编辑:我假设每个

impl Trait
都更改为不同独特泛型类型(与其他
impl Trait
或以前的泛型不重叠)。违反这一点显然会被破坏,感谢@啊鹿Dizzyi 指出这一点。

我在这里列出了

impl Trait
更改为通用的案例列表(我认为是详尽的)。如果其中任何一个可能在下游断裂,请说明如何断裂。如果我错过了某些案例,请解释它是否损坏。

  1. 仅更改
    impl Trait
// before
fn foo(_: impl Trait) {}

// after
fn foo<T: Trait>(_: T) {}
  1. 很多
    impl Trait
    ,但只改变其中一些
// before
fn foo(_: impl Trait1, _: impl Trait2, _: impl Trait3) {}

// after
fn foo<T1: Trait1, T2: Trait2>(_: T1, _: T2, _: impl Trait3) {}
  1. 很多
    impl Trait
    ,全部改变
// before
fn foo(_: impl Trait1, _: impl Trait2, _: impl Trait3) {}

// after
fn foo<T1: Trait1, T2: Trait2, T3: Trait3>(_: T1, _: T2, _: T3) {}
  1. 一些通用类型,更改一些
    impl Trait
    ,但至少保留一个
// before
fn foo<T1: Trait1>(_: T1, _: impl Trait2, _: impl Trait3) {}

// after
fn foo<T1: Trait1, T2: Trait2>(_: T1, _: T2, _: impl Trait3) {}
  1. 一些通用类型,改变所有
    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) {}
rust semantic-versioning
1个回答
1
投票

发生这种情况的一种情况是,当你想要函数接受两个都实现某些特征的参数时

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`.
© www.soinside.com 2019 - 2024. All rights reserved.