首页 > 其他分享 >rust学习十一.1、泛型(通用类型)

rust学习十一.1、泛型(通用类型)

时间:2024-11-21 15:45:53浏览次数:1  
标签:十一 通用 list 类型 let largest 泛型 rust

这是和大部分的语言差不多的一个概念,只不过实现上有一些区别而已。

所以,如果学过java,c#,c++,那么这应该很好理解。

虽然如此,还是有不少内容需要记录,只不过内容有一点小多。

注意:这是入门级别内容,只能涉及到一些基本的方面。

一、定义

英文 Generic /generics, 中文翻译为通用类型/泛型, 和java等语言是差不多的一个概念。

注意:实际指的是对象(这里引用了java等oop的概念)的属性和方法可以接收通用类型,不是指对象本身是通用的。只不过

通过对属性和方法的通用化,实现某种程度的对象通用。

 

通用类型的引入产生了巨大的方便

在么有通用类型的情况下,一个带有一个参数的函数/方法只能适用于一种类型,如果类似的函数有多个,那么必然照成了一定的工作量。

所以,通用类型的存在就是为了让一个对象(属性和其中方法)、方法可以适用于多种类型。 具体实现方式见后文。

如果您学过其它语言,这个就非常容易理解了。

 

二、实现通用类型

和java类似,rust可以在对象(struct,enum等)和方法中使用通用类型符号。

本文的例子基本来源于相关书籍。

以下那么的例子,其实归结起来就是两个:方法中使用通用类型、变量/属性中使用通用类型。

2.1 函数中使用通用类型

特别注意

rust自己把其它语言中的函数、方法做了区分

  • 函数(function)  -  不属于结构、枚举的功能体
fn this_is_function()->i32{
   10;
}

fn main(){
  this_is_function();
}

 

      大体上可以这么理解。

  • 方法(method)-属于结构、媒体的功能体
#[derive(Debug)]
struct Cube{
    length: u32,
    width: u32,
    height: u32,
}
impl Cube{
    fn volume(&self) -> u32{
        return self.length * self.width * self.height;
    }
    fn is_bigger_than(&self, other: &Cube) -> bool{
        return self.volume() > other.volume();
    }
}

 

虽然二者的语法一致,包括关键字等,但是核心的区别是:函数不属于某个对象(结构、枚举等),只会属于某个模块。

 

这个例子,对于从来没有接触过通用类型的工程师而言,非常有用,因为它说清楚了使用了通用类型的函数和一般函数的区别。

这是典型的:口水说干了,不如一个例子

例_2.1

 fn largest_i32(list: &[i32]) -> &i32 {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

fn largest_char(list: &[char]) -> &char {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

//使用上通用类型后的取最大值函数,这里只要一个即可
//如果没有对T进行限定,会报告异常: binary operation `>` cannot be applied to type `&T`
//所以必须使用 T: xxxx的方式进行限定
fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];
    let char_list = vec!['y', 'm', 'a', 'q'];

    let result = largest_i32(&number_list);
    println!("最大数值 of {:?} is {result}", number_list);
    let result = largest_char(&char_list);
    println!("最大字符 of {:?} is {result}", char_list);

    println!("使用带通用类型参数的函数来计算最大值");
    let result = largest(&number_list);
    println!("最大数值 of {:?} is {result}", number_list);
    let result = largest(&char_list);
    println!("最大字符 of {:?} is {result}", char_list);
}

 在上例中,函数largest利用通用类型T实现了整数取最大、字符取最大的功能。

如果有返回值,且返回类型也是通用类型,则必须在方法名后带上<T>之类的,这一点和java等类似

2.2 结构体中使用通用类型

道理同2.1,稍微列举下。

#[derive(Debug)]
struct Family<数字,字符>{
    qty:数字,
    name:字符
}

fn main() {
    let family = Family{
        qty: 10,
        name: "A".to_string(),
    };
    println!("{:#?}", family);

    let mf= Family{
        qty:"10个",
        name:"爸爸,妈妈,儿子,女儿"
    };
    println!("{:#?}", mf);
}

 

如果有结构方法,且 impl后的结构有带上通用类型符号,则必须在impl后直接带上<A,B,C...>之类的,同结构体自身一样

impl<数字,String>  Family<数字,String> {
    fn double(&self){
        &self.qty;
    }
}

也就是说如果Family有限定类型,则impl后必须带上一样的<T,U...>

 

如果Family不用通用类型符号,则impl也不必带

impl  Family<i32,String> {
    fn get(&self){
        &self.qty;
    }
}

 

2.3 枚举中使用通用类型

道理同2.1,稍微列举下。

#[derive(Debug)]
enum Position<A,B,C>{
    普通成员(A),
    组长(B),
    经理(C),
    总监(C),
    老板(A,B,C)
}

fn main() {
    //如果你只使用部分通用类型符号,那么必须使用":xxx"语法来列明其它通用符号的类型
    //这种情况应该是使用于其它情况下
    let p:Position<i32, i32, i32> = Position::普通成员(10); //如果直接定义为 let p=Position::普通成员(10);会报错 type annotations needed for `Position<i32, _, _>` 
    println!("{:?}",p);
    let boss=Position::老板("lml",2045,[10,20,30,80,90,95,99,100]);
    println!("{:?}",boss);
}

 

这里需要注意是:如果实例变量只是使用部分通用类型符号,那么必须使用":xxx"语法来列明其它通用符号的类型。

否则会报告类似这样的错误: type annotations needed for `Position<i32, _, _>`

这是因为rust必须在编译期间确定具体类型。

 

枚举定义方法,如果不用通用类型,如下,否则同结构。

impl Position<i32, i32, i32> {
    fn get_position(&self)->i32{
        match self {
            Position::普通成员(a) => *a,
            Position::组长(a) => *a,
            Position::经理(a) => *a,
            Position::总监(a) => *a,
            _ => 100
        }
    }
}

 

2.4 其它类型中使用通用类型

除了广泛使用的结构、枚举类型,rust的其它类型也可以使用通用类型。

只不过,这些类型通常需要作为结构枚举等复杂类型(对象)的属性成员,才可以使用这些通用类型符号。

struct Box<A,B,C>{
    names:(A,B,C),
    scores:HashMap<B,C>,
    days:[C;5],
    tools:Vec<A>
}

 

它们自己单独定义是没有的,例如不能定义 let name:Vec<T>=Vec<i32>::new();

三、限定类型范围

在例子2.1中,函数largest的,必须定义为:

largest<T:std::cmp::PartialOrd>(list: &[T]) -> &T 这是为了限定T的类型范围,否则会报告异常,具体什么异常,需要看情况而定。   这个例子告诉我们:rust也面临其它语言一样的问题,这个问题就是在某些场合需要限定通用类型的类型范围,因为有的行为不适合于所有类型。   在本文中,限定类型范围的方式只有这个。 但实际上,rust有多种方式,后续会补充完善!

四、在运行时判断通用类型的实际类型

rust好像不支持这个。

rust是静态类型语言,这意味着它在编译的时候,就需要确定变量实例的类型。

而这也意味着,它不怎么需要在运行时候:动态判定一个变量实例的具体的类型。

如果它那么做,可能会违法它的核心理念:安全之上。

 

说到这个问题,不得不提到java。

java虽然是名义上的静态类型语言,但是由于java的特殊性(一切都是类),它有办法通过为对象设置属性来判断一个实例的类型。

java可以利用instaneof来判断。

rust没有这种机制,至少学到这里是没有的!

然而rust也有变通的方式改变这个,此处不论!

五、编译与性能

这个比较有意思。

在入门级的书籍中,我们就能了解到这个事实:

  1. 泛型并不会使程序比具体类型运行得慢
  2. Rust 通过在编译时进行泛型代码的 单态化monomorphization)来保证效率。单态化是一个通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程

monomorphization这是rust人制造的一个词汇,大体由mono(单声道)+morph(变化)+zation(化,使得...成立)构成,表面意思是:单声道变化

只有结合例子才知道,其实就是中文"具体化"的意思:针对适配的具体类型,逐个编译,使得每一种情况都被考虑到。

这种过程很类似设计模式中工厂模式-对外公布一个接口,对内则实现各种工厂。

还是结合例子(来自原书籍),再看例_2.1:

fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

 在上例中,如果只有一个通用类型函数,而没有具体的,那么,在编译的时候,会根据相关环境,编译出若干个函数出来(这里是两个):

 fn largest_i32(list: &[i32]) -> &i32 {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

fn largest_char(list: &[char]) -> &char {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

 

当然,大体是这么一个意思。这也是我自己的猜测。

书本上的例子更加直接,是枚举的。

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}

 

意思就是,根据main的情况,自动反编译出Option的两个具体。

考虑到这种,需求,所以,不难理解为什么rust采用静态实现,为什么不支持动态判断变量实例的类型(待确认)。

六、小结

  1. 通用类型针对的是对象属性,方法/函数参数,不是对象、方法本身。这个基本同java等语言
  2. 可以使用合法的标识符来表示通用类型,不必一定是K,T,V之类的,包括单词,汉语词语等。这个方面和JAVA等语言类似
  3. rust并没有对方法/函数一或者对象可以定义的通用类型进行个数限制
  4. 如果要对函数返回类型使用通用类型,则必须在函数名后跟上诸如<T>这样的字符,这个方式和java的类似。当方法不需要(注意函数和方法的区别)
  5. rust一样存在通用类型的常见问题:要么定义的时候限定通用类型的类型,要么是运行时在方法/函数体中使用类似 instanceof(java)之类的判断泛型的实际类型。rust只能在编码的时候进行限制
  6. 但rust可以使用类似 T:xxxx的方式限定类型范围,或者T:xxxx+****+???+..,,其中xxxx,****,???都是表示特定类型/操作
  7. 截止本章为止,rust并没有?这样的通配符,可以用于通用类型中。java有类似 ? super/extends Grade这样的用法,可用于限定参数类型
  8. rust通过在编译阶段的行为(单态化/具体化)来实现通用。但这种机制是不同于java之类的语言的,虽然它们都是静态类型语言。

注意:由于本文是按照相关书籍顺序编写的,所以很多内容是具有一定局限性的。 例如rust用于限定通用类型范围的方式不是只有一种。后续会补充有关内容。

 

标签:十一,通用,list,类型,let,largest,泛型,rust
From: https://www.cnblogs.com/lzfhope/p/18555390

相关文章

  • ExpressionTreeHelper 表达式树泛型委托拷贝方法
    varpeople=newPeople(){Id=11,Name="Richard",Age=31};intcount=1_000_000;varcommon=HiPerfTimer.Execute(()=>{for(inti=0;i<count;i++){varitem=newPeopleCopy(){......
  • 腾讯云双十一攻略:最全省钱秘籍,带你领略云端购物的最高性价比!
    腾讯云双十一活动入口(地址:https://mc.tencent.com/XG6bYV4u)。双十一即将来临,作为数字化转型的关键工具,腾讯云在这一年一度的购物狂欢中也推出了重磅优惠活动!但面对海量的产品和促销规则,很多人可能不知道如何抓住最划算的机会。那么,如何在腾讯云双十一活动中做到精准出击,最大程......
  • 第十一课 接口测试之postman11.1
    一、介绍postmanPostman是一个网页调试工具,也可以调试css、html等Postman的操作环境环境:PostmanMac、WindowsX32、WindowsX64、Linux系统、postman浏览器扩展程序、postmanchrome应用程序Postman下载:https://www.postman.com/downloads/二、postman安装:略三、postman......
  • 2024年腾讯云双十一薅羊毛最强攻略:错过一次又得等一年!
    2024年腾讯云双十一活动为用户提供了丰富的云产品和优惠福利,以下是一份省钱、省心、省力的购买攻略,帮助大家制定必抢清单:一、活动时间与入口活动时间:即日起至2024年11月30日23:59:59,具体以页面变更为准。活动入口:腾讯云双十一活动页面二、优惠活动概览1.服务器限时秒杀:每......
  • 2024年阿里云年终活动内容详解,阿里云双十一活动参与攻略
    2024年阿里云年终活动内容详解,阿里云双十一活动参与攻略。要参与2024年阿里云双十一活动,您可以按照以下步骤进行:一、前期准备注册/登录阿里云账号访问阿里云官网,根据页面提示完成账号注册或登录。了解活动信息在阿里云官网的活动页面或相关公告中,了解双十一活动的具体信......
  • 腾讯云服务器价格多少钱?腾讯云双十一活动服务器多少钱一年?
    腾讯云服务器价格多少钱?腾讯云双十一服务器多少钱一年?腾讯云双十一服务器多少钱一个月?一个腾讯云双十一服务器多少钱?腾讯云双十一活动服务器年付、月付租用价格配置表在哪里查看?2024年腾讯云双十一活动的入口在哪里?2024年腾讯云双十一活动时间是什么时候?2024年腾讯云双十一活动......
  • 泛型编程之乘法
    埃及乘法目标奇数odd被乘数和乘数尾递归函数r+na......
  • 论文HyperEnclave An Open and Cross-platform Trusted Execution Environment学习
    论文原文链接原文都是英文的,先翻译一遍,在翻译的过程中阅读和理解。HyperEnclave:一个开放的跨平台可信执行环境摘要学术界和工业界已经提出了许多可信执行环境(TEEs)。然而,它们中的大多数都需要特定的硬件或固件更改,并且绑定到特定的硬件供应商(如Intel、AMD、ARM和IBM)。在本文中......
  • rust学习十、异常处理(错误处理)
    在书籍中,中文译者翻译为错误,这是因为原文是"Error"。但在很多语言中,都是书写为异常。一、概述rust的错误处理与众不同,前文已经提及:大家称为异常,它称为错误。 不可恢复的错误,可以大体称为panic(恐慌)!太率性了....那么我们的问题是:除了一些的确不可处理的异常,rust是否也和......
  • Rust impl关键字(实现封装、继承和多态等功能)(Rust关联类型、impl关联类型、Rust静态方
    文章目录Rust中的`impl`关键字详解什么是`impl`关键字?`impl`的基本语法示例:为结构体实现方法`impl`与特征(Trait)(为类型实现通用接口)示例:为类型实现特征`impl`与关联类型(关联类型使得在特征中定义的一些类型可以在实现时具体化)示例:使用关联类型`impl`与静态方法(不带self......