6.Rust中的泛型

相信很多C++程序员对泛型编程是非常熟悉的,我本来也是觉得不需要再特别介绍泛型这部分,因为其实都大同小异。但是考虑到部分读者可能不太熟悉,所以还是专门用一期来介绍泛型。

一、什么是泛型编程

C/C++、Rust都是强类型语言,在对数据进行处理时,必须明确数据的数据类型。但是很多时候,比如链表这种数据结构,我们可以是整型数据的链表,也可以是其他类型,我们可能就会写出重复的代码,仅仅是数据类型不同而已。还有比如说排序,算法里处理数据,也是同样的道理。

所以,我们为了简化代码。我们将类型抽象成一种“参数”,数据和算法针对于这种抽象的类型来实现,而不是具体的类型。当我们需要使用时再去具体化、实例化。

下面举一个例子:

//不使用泛型
//针对于整型数据
fn findmax_int(list : &[i32]) -> i32 {
    let mut max_int = list[0];
    for &i in list.iter() {
        if i > max_int {
            max_int = i;
        }
    }
    max_int
}

//针对于char数据
fn findmax_char(list : &[char]) -> char {
    let mut max_char = list[0];
    for &i in list.iter() {
        if i > max_char {
            max_char = i;
        }
    }
    max_char
}



fn main() {
    let v_int = vec![2, 4, 1, 5, 7, 3];
    println!("max_int: {}", findmax_int(&v_int));
    let v_char = vec!['A', 'C', 'G', 'B', 'F'];
    println!("max_char: {}", findmax_char(&v_char));
}

运行结果:

max_int: 7
max_char: G

可以看到两个函数基本上是一样的,下面我们采用泛型的方式来简化代码:

fn find_max<T> (list : &[T]) -> T {
    let mut max = list[0];
    for &i in list.iter() {
        if i > max {
            max = i;
        }
    }
    max
}



fn main() {
    let v_int = vec![2, 4, 1, 5, 7, 3];
    println!("max_int: {}", find_max(&v_int));
    let v_char = vec!['A', 'C', 'G', 'B', 'F'];
    println!("max_char: {}", find_max(&v_char));
}

编译报错:

error[E0369]: binary operation `>` cannot be applied to type `T`
  --> src\main.rs:27:14
   |
27 |         if i > max {
   |            - ^ --- T
   |            |
   |            T
   |
   = note: `T` might need a bound for `std::cmp::PartialOrd`

意思就是>这个运算符需要PartialOrd,这个的意思是你用比较符号,得能比较的数据类型。

那我们加上:

fn find_max<T : PartialOrd> (list : &[T]) -> T {
    let mut max = list[0];
    for &i in list.iter() {
        if i > max {
            max = i;
        }
    }
    max
}

还是编译报错:

error[E0508]: cannot move out of type `[T]`, a non-copy slice
  --> src\main.rs:25:19
   |
25 |     let mut max = list[0];
   |                   ^^^^^^^
   |                   |
   |                   cannot move out of here
   |                   move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait
   |                   help: consider borrowing here: `&list[0]`

error[E0507]: cannot move out of a shared reference
  --> src\main.rs:26:15
   |
26 |     for &i in list.iter() {
   |         --    ^^^^^^^^^^^
   |         ||
   |         |data moved here
   |         |move occurs because `i` has type `T`, which does not implement the `Copy` trait
   |         help: consider removing the `&`: `i`

就是说这两个操作需要类型具有Copy语义。因此加上对类型的Copy语义要求:

fn find_max<T : PartialOrd + Copy> (list : &[T]) -> T {
    let mut max = list[0];
    for &i in list.iter() {
        if i > max {
            max = i;
        }
    }
    max
}



fn main() {
    let v_int = vec![2, 4, 1, 5, 7, 3];
    println!("max_int: {}", find_max(&v_int));
    let v_char = vec!['A', 'C', 'G', 'B', 'F'];
    println!("max_char: {}", find_max(&v_char));
}

成功运行:

max_int: 7
max_char: G

非常滴方便!

其实泛型的话,还是比较复杂的一个概念,我也是听侯捷老师的课的时候才感觉醍醐灌顶,感兴趣的人可以去看一下侯捷老师关于C++ STL的课程,里面有讲到很多泛型编程的细节,包括泛化、偏特化等等。如果找不到资源可以后台留言或者加我微信哈。

下面开始介绍Rust中的泛型。

二、数据结构中的泛型

例如结构体、枚举吧:

Option就是一个泛型嘛。

enum Option<T> {
	Some(T),
	None,
}

结构体:

struct A<T> {
	data1 : T,
	data2 : T,
	data3 : i32
}

但是声明了泛型就必须使用:

struct A<T> {
	data : i32
}

这样就会报错。

在结构体方法中泛型:

struct A<T> {
    x : T,
    y : T
}

impl <T> A<T> {
    fn get_x(&self) -> &T {
        &self.x
    }

    fn get_y(&self) -> &T {
        &self.y
    }
}


fn main() {
    let a = A { x : 1, y : 2};
    println!("a.x: {}, a.y: {}",a.get_x(), a.get_y());
    let b = A { x : 'a', y : 's'};
    println!("b.x: {}, b.y: {}",b.get_x(), b.get_y());
}

运行结果:

a.x: 1, a.y: 2
b.x: a, b.y: s

这个程序很好理解。下面再举一个例子。

struct A<T, S> {
    x : T,
    y : S
}



impl <T, S> A<T, S> {
    //通过两个不同的A来创建一个新的A
    fn crete_newA<M, N>(self, other : A<M, N>) -> A<T, N> {
        A {
            x : self.x,
            y : other.y
        }
    }
}


fn main() {
    let a1 = A { x : 's', y : 2.2 };
    let a2 = A { x : 3.5, y : 5 };
    let a3 = a1.crete_newA(a2);
    println!("a3.x: {}, a3.y: {}", a3.x, a3.y);
}

运行结果:

a3.x: s, a3.y: 5
三、函数中的泛型

我们最开始举的例子就是咯。

四、泛型约束

第一部分举的例子中的PartialOrd + Copy就是泛型约束。

那么什么是泛型约束呢?

Rust中的泛型和C++中的template是比较相似的,但是差别很大。C++是在实例化的时候进行类型检查。而Rust则是当场进行检查,所以需要用户提供合理的“泛型约束”,比如你需要使用“>”时,需要数据类型能够使用“>”运算符。

既然是简单介绍,这期就到这里吧,毕竟在以后的学习中,泛型无处不在。

欢迎关注微信公众号:Rust编程之路,持续更新Rust、C++相关文章
在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大脑白质

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值