zoukankan      html  css  js  c++  java
  • Rust泛型相加

    在学习了Rust的泛型后, 我想写一个demo code用来练习。于是想到我要相加两个数,无论是i8, i32, isize或是float类型。 于是很自然的想到如下实现,结果报错 : 

    error[E0369]: cannot add `T` to `T`  

    编译为什么会报错呢? 

     1 fn add<T>(a:T,b:T) -> T {
     2     let c = a + b;
     3     c
     4 }
     5 
     6 fn main(){
     7     let result = add(3,2);
     8 
     9     println!("add result : {}",result);
    10 }

     在解释这个问题之前,我们可以这样假设,泛型是一种抽象,虽然我们传入的是基本类型,但是架不住调用这个函数的人传其它的Type进去。这样一来,比如泛型结构体相加是个什么鬼呢?
    1 fn main() {
    2   struct  Int_a<T>{a:T};
    3   struct  Int_b<T>{b:T};
    4   let  A:Int_a<T> = {3};
    5   let  B:Int_b<T> = {2};
    6   add(A,B);
    7 }

    既然泛型无法相加,那基本类型的泛型相加应该要如何实现呢? 如下,无符号整形,有符号整形,浮点类型相加 :

    1 add(3,2);
    2 add(3.1,2,3);
    3 add(5,-10);

    首先映入脑海的是,如果利用泛型约束,是不是就可以做到了呢。为此,我们可以测试如下,结果编译又报错 :

    error[E0404]: expected trait, found builtin type `i8`
     
     1 fn add<T:i8>(a:T,b:T) -> T {
     2     let mut c = a + b;
     3     c
     4 }
     5 
     6 fn main(){
     7     let result = add(3,2);
     8 
     9     println!("add result : {}",result);
    10 
    11     let result = add(5.2,3.3);
    12     println!("add result float :{}",result);
    13 }

    好吧,在《Rust by example》中,我们看到这样一句话 :When working with generics, the type parameters often must use traits as bounds to stipulate what functionality a type implements
    必须要使用Trait做为约束才可以。 为什么会有这种规定呢? 按我的理解,如果用具体类型做为约束,那泛型完全失去了抽象的能力,上面的函数退化为如下,这样就没有意义了 :

    1 fn add (a:i8,b:i8) -> i8 {
    2       let mut c = a + b;
    3       c
    4 }

    至此, 还是没能解决我们泛型相加的问题.  不过,Rust错误信息给了我们一个提示,泛型需要使用trait约束,那我们就声明一个trait作为约束好了。很自然的我们能想到,要怎样定义trait才能达到约束的目的。我们只想限定基本类型,那就是说只有实现了Add trait的类型才能作为我们的泛型约束。

     1 trait Add {
     2     type Output;
     3 }
     4 impl Add for i8{
     5     type Output = i8;
     6 }
     7 impl Add for i16{
     8     type Output = i16;
     9 }
    10 impl Add for u32{
    11     type Output = u32;
    12 }
    13 impl Add for usize{
    14     type Output = usize;
    15 }
    16 
    17 fn add<T:Add<Output=T>>(a:T,b:T) -> T {
    18     let mut c = a + b;
    19     c
    20 }
    21 
    22 fn main(){
    23     let result = add(3i8,2i8);
    24 
    25     println!("add result i8: {}",result);
    26 
    27     let result = add(5u32,3u32);
    28     println!("add result u32 :{}",result);
    29 }

    很不幸,这样还是报错:

    error[E0369]: cannot add `T` to `T`
    help: consider further restricting this bound
    fn add<T:Add<Output=T> + std::ops::Add<Output = T>>(a:T,b:T) -> T {
     
    按照提示,添加std::ops::Add后,编译通过,测试结果无误! 只是没有明白为什么要用std::ops::Add限定才能编译过呢?  这个问题留待后面想清楚后再写。 
    1 fn add<T:Add<Output=T>+std::ops::Add<Output = T>>(a:T,b:T) -> T {
    2     let c = a + b;
    3     c
    4 }
  • 相关阅读:
    P1410 子序列 (动态规划)
    P2085 最小函数值 (堆)
    [ZJOI2007]棋盘制作 (单调栈,动态规划)
    [ZJOI2005]午餐 (贪心,动态规划)
    黑匣子_NOI导刊2010提高 (对顶堆)
    [BZOJ1455] 罗马游戏 (左偏树||并查集)
    P1651 塔 (动态规划)
    两类斯特林数 (组合数学)
    从编程到工程
    失败的过程也是过程
  • 原文地址:https://www.cnblogs.com/linuxcat/p/15244955.html
Copyright © 2011-2022 走看看