您现在的位置是:首页 >技术杂谈 >RUST 每日一省:泛型约束——trait网站首页技术杂谈

RUST 每日一省:泛型约束——trait

许汶强 2023-07-02 16:00:03
简介RUST 每日一省:泛型约束——trait

        使用泛型编程时, 很多情况下的行为并不是针对所有类型都实现的,用trait作为泛型的约束。例如,我们编写一个判断两个变量大小的泛型函数,编译时,会运行如下错误。

fn max<T>(a: T, b: T) -> T {
    if a < b {
        b
    } else {
        a
    }
} 

fn main() {
    let m = max(1, 2);
}


error[E0369]: binary operation `<` cannot be applied to type `T`
  --> src/main.rs:14:10
   |
14 |     if a < b {
   |        - ^ - T
   |        |
   |        T
   |
help: consider restricting type parameter `T`
   |
13 | fn max<T: std::cmp::PartialOrd>(a: T, b: T) -> T {
   |         ++++++++++++++++++++++

        这个编译错误是说, 由于泛型参数T没有任何约束——如果我们填入两个Struct类型,如何比较呢, 因此编译器认为a<b这个表达式是不合理的, 因为它只能作用于支持比较运算符的类型。编译器也进行了提示,只有impl了PartialOrd的类型, 才能支持比较运算符。修正如下。

fn max<T:PartialOrd>(a: T, b: T) -> T {
    if a < b {
        b
    } else {
        a
    }
} 

fn main() {
    let m = max(1, 2);
    
}

trait约束语法

trait约束的语法如下:
fn generic<T: MyTrait + MyOtherTrait + SomeStandarTrait>(t: T)
{

        todo!()

}
 

        如果泛型参数有多个trait约束,通过+语法来指定多个trait约束;拥有多个泛型参数的函数,在函数名和参数列表之间会有很长的trait约束信息,使得函数签名可读性差。Rust提供where关键字来处理这种情况。代码如下,

fn max<T>(a: T, b: T) -> T
    where T: PartialOrd
{
    if a < b {
        b
    } else {
        a
    }
}

总结,泛型参数约束有两种语法:
(1) 在泛型参数声明的时候使用冒号: 指定;
(2) 使用where子句指定。

fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {}

fn some_function<T, U>(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
{}

        在有了“泛型约束”之后, 编译器不仅会在声明泛型的地方做类型检查, 还会在调用的地方做类型检查。例如当用户调用时,编译器会分析泛型函数当场检查类型的合法性,此时泛型的类型检查就完成了。

fn max<T:PartialOrd>(a: T, b: T) -> T {
    if a < b {
        b
    } else {
        a
    }
} 

struct T1 {
    value: i32
}

#[derive(PartialOrd,PartialEq)]
struct T2 {
    value: i32
}

fn main() {
    let m = max(1, 2);
    let t11 = T1{value:1};
    let t12 = T1{value:1};
    let m = max(t11, t12);

    let t21 = T2{value:1};
    let t22 = T2{value:1};
    let m = max(t21, t22);
    
}

   = help: the trait `PartialOrd` is not implemented for `T1`
note: required by a bound in `max`
  --> src/main.rs:31:10
   |
31 | fn max<T:PartialOrd>(a: T, b: T) -> T {
   |          ^^^^^^^^^^ required by this bound in `max`
help: consider annotating `T1` with `#[derive(PartialOrd)]`
   |
3  | #[derive(PartialOrd)]
   |

        我们看到定时泛型函数max时指定了PartialOrd,没有错误;但是在我们调用的时候,由于T1没有实现PartialOrd,导致调用失败了。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。