rust 泛型

目录

1,泛型函数

2,特征约束

(1)特征约束

(2)多重约束

(3)where

(4)子特征的约束推导出父特征

(5)模板类型的默认特征约束

(6)trait类型的入参

3,泛型数据结构

(1)泛型结构体

(2)泛型结构体实现trait的偏特化实现

(3)泛型结构体实现trait的泛型实现、带type的特征约束

(4)泛型枚举

4,常数泛型参数

5,泛型trait

6,trait内的泛型函数

7,trait类型的返回值

8,trait对象


1,泛型函数

下面是一个手动实现vec翻转的例子:

fn vector_reverse<T:Clone> (v:&Vec<T>)->Vec<T>{
    let mut ans = Vec::new();
    let mut i = v.len();
    loop {
        if i==0{
            break;
        }
        i-=1;
        ans.push(v[i].clone());
    }
    return ans;
}

这里一共有3处类型参数T

第一个vector_reverse<T:Clone>表示这个泛型函数的的参数就是T

第二个v:&Vec<T>表示入参是T类型的vec

第三个->Vec<T>表示返回值是T类型的vec

也可以使用多个模板参数:

fn f<T:Clone, S:Copy> (v:&Vec<T>,s:&Vec<S>)->i32
{
    return 0;
}

2,特征约束

(1)特征约束

vector_reverse的例子中,要求模板参数T具有Clone特征,这就是一个特征约束。

泛型函数要保证自身是能编译的,而不取决于调用代码。所以,泛型函数内部对T的约束条件,都通过指明T所包含的trait的方式进行说明。

(2)多重约束

如果T需要多个trait,采用加号把trait连接起来。

(3)where

如果特征约束比较多,为了不影响阅读,可以把约束提到函数头的末尾:

fn f<T, S> (v:&Vec<T>,s:&Vec<S>)->i32
    where T:Clone, S:Copy
{
    return 0;
}

(4)子特征的约束推导出父特征

fn f2<T:Ord+Clone>(arr:Vec<T>)->T{
    if(arr[0]==arr[1]){
        return arr[1].clone();
    }
    return arr[0].clone();
}

Ord特征中并没有eq函数,但是Ord特征间接继承了PartialOrd,所以有Ord特征的类型肯定是可以使用==的。

(5)模板类型的默认特征约束

对于绝大部分trait,模板类型都是默认不包含该trait的,需要特征约束才能说明该类型具有该trait。

而Sized是个反例,模板类型是默认包含Sized这个特征的,需要 ?Sized 才能说明可以不具有该特征。

pub trait Borrow<Borrowed: ?Sized> {
......
}

(6)trait类型的入参

fn exec(x:impl Display){
    print!("{}",x);
}

fn main() {
    exec(6);
}

这是一个语法糖,等价于:

fn exec<T:Display>(x:T){
    print!("{}",x);
}

3,泛型数据结构

数据结构要想好用,都得是泛型的。

无论是c++ STL还是rust std,里面所有的数据结构都是泛型的,c++和rust的结构体也类似,可以是泛型的也可以是非泛型的。

(1)泛型结构体

例如 Vec

pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
    buf: RawVec<T, A>,
    len: usize,
}

(2)泛型结构体实现trait的偏特化实现

trait VecEx {
    fn get_zeros_num(&self) -> i32;
}
impl VecEx for Vec<i32> {
    fn get_zeros_num(&self) -> i32{
        let mut ans = 0;
        for i in 0..self.len() {
            if (self[i] == 0) {
                ans+=1;
            }
        }
        return ans;
    }
}

(3)泛型结构体实现trait的泛型实现、带type的特征约束

use std::ops::Sub;
trait VecEx {
    fn get_zeros_num(&self) -> i32;
}
impl<T:Clone+Sub<Output=T>+PartialEq> VecEx for Vec<T> {
    fn get_zeros_num(&self) -> i32{
        let mut ans = 0;
        for i in 0..self.len() {
            if (self[i] == self[0].clone() - self[0].clone()) {
                ans+=1;
            }
        }
        return ans;
    }
}

(4)泛型枚举

例如option、result

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

pub enum Result<T, E> {
    Ok(T),
    Err(E),
}

4,常数泛型参数

和c++类型,常数也可以作为泛型参数

fn f<T:Clone,const N:usize>(arr:[T;N])->T{
    return arr[0].clone();
}

fn main() {
    let x = [1,2,3];
    let y = [1.5,2.5];
    assert_eq!(f(x),1);
    assert_eq!(f(y),1.5);
}

作为泛型参数的常数类型,可以是所有整数类型、bool类型、char类型

5,泛型trait

给结构体实现泛型trait,会遇到一些比较复杂的情况

(1)同名且返回值相同

struct S<T, T2>
{
    x:T,
    y:T2
}
trait MyTrait<T>{
    fn f(&self)->i32;
}

impl<T> MyTrait<T> for T{
    fn f(&self)->i32{
        -1
    }
}

impl<T,T2> MyTrait<T> for S<T,T2>{
    fn f(&self)->i32{
        1
    }
}

fn main() {
    let x=S{x:1, y:1};
    assert_eq!(<S<i32,i32> as MyTrait<i32>>::f(&x), 1);
    assert_eq!(<S<i32,i32> as MyTrait<S<i32,i32>>>::f(&x), -1);
    println!("end");
}

这样,实际上给S实现了2份MyTrait,必须用trait名调用函数。

(2)同名但返回值不同

参考Rc中的borrow函数

6,trait内的泛型函数

struct S{
    x:i32,
    y:f32
}

trait Tr {
    fn f<T:Display>(x:& T){}
}

impl Tr for S{
    fn f<T:Display>(x:& T)
    {
        println!("data = {}", x);
    }
}

fn main() {
    let mut s=S{x:5, y:7.7};
    S::f(&s.x);
    S::f(&s.y);
}

这个例子中,类型T是靠入参自动推导出来的。

7,trait类型的返回值

fn f()->impl Display{
    4546
}
fn exec<T:Display>(x:T){
    print!("{}",x);
}

fn main() {
    let x = f();
    exec(x);
}

f可以返回任意具有Display特征的类型的数据。

8,trait对象

用dyn关键字,可以把一个trait当做一个数据类型。

前提条件:该trait的所有函数都有self参数。

struct S{
    x:i32
}
struct S2{
    y:f32
}

trait Ft{
    fn f(&self){}
    fn f2(&self){}
}
impl Ft for S{
    fn f(&self){
        print!("{}",self.x);
    }
}
impl Ft for S2{
    fn f(&self){
        print!("{}",self.y);
    }
}

fn exec(x: &dyn Ft) {
    x.f();
}

fn main() {
    let s1 = S{x:5};
    let s2=S2{y:2.3};
    exec(&s1);
    exec(&s2);
}

相关推荐

  1. rust

    2024-01-30 22:08:03       71 阅读
  2. Rust---(Generics)

    2024-01-30 22:08:03       32 阅读
  3. 学习 Rust 的第 16 天:类型

    2024-01-30 22:08:03       36 阅读
  4. <span style='color:red;'>泛</span><span style='color:red;'>型</span>..

    ..

    2024-01-30 22:08:03      61 阅读
  5. <span style='color:red;'>泛</span><span style='color:red;'>型</span>

    2024-01-30 22:08:03      27 阅读
  6. Rust 使用过程中的 <T> 和 ::<T> 的区别

    2024-01-30 22:08:03       41 阅读
  7. 14 # 类与约束

    2024-01-30 22:08:03       53 阅读
  8. (标签)

    2024-01-30 22:08:03       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-30 22:08:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-30 22:08:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-01-30 22:08:03       82 阅读
  4. Python语言-面向对象

    2024-01-30 22:08:03       91 阅读

热门阅读

  1. Ubuntu 下进行系统备份与迁移

    2024-01-30 22:08:03       59 阅读
  2. HarmonyOS--@ObjectLink和@Observed

    2024-01-30 22:08:03       67 阅读
  3. vue 和 react技术选型

    2024-01-30 22:08:03       50 阅读
  4. 51单片机智能小车

    2024-01-30 22:08:03       50 阅读
  5. 多线程面试合集

    2024-01-30 22:08:03       55 阅读
  6. 华为策略路由+NQA配置

    2024-01-30 22:08:03       50 阅读
  7. qt信号与槽机制及使用demo

    2024-01-30 22:08:03       43 阅读