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 }

 

posted @ 2021-09-10 00:04  春江水暖  阅读(606)  评论(0编辑  收藏  举报