Rust简明教程第四章-其他类型泛型

news/2024/7/8 7:52:01 标签: rust, 开发语言, 后端

观看B站软件工艺师杨旭的rust教程学习记录,有删减有补充

枚举

枚举类型可以让我们的程序使用一些固定长度和固定数值的变量值范围

enum 枚举

枚举类型中的值被称为变体

rust">enum IpAddrKind{
    V4,//变体
    V6,//变体
}
fn main(){
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;
    route(four);
    route(six);
    route(IpAddrKind::V6);
}
fn route(ip_kind:IpAddrKind){
}

struct存储数据

rust">enum IpAddrKind {
    V4, //变体
    V6, //变体
}
struct IpAddr {
    kind: IpAddrkind,
    address: String,
}
fn main() {
    let home = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };
    let loopback = IpAddr {
        kind: IpAddrKind::v6,
        address: String::from("::1"),
    };
}

将数据添加到变体

rust">enum IpAddrKind{
    V4(u8,u8,u8,u8),
    V6(String),
}
fn main() {
    let home=IpAddrKind::V4(127.0.0.1);
    let loopback = IpAddrKind::V6(String::from("::1"));
}

嵌入其他类型

rust">enum Message {
    Quit,
    Move { x: i32, y: i32 }, //匿名结构体
    Write(String),
    ChangeColor(i32, i32, i32),
}
fn main() {
    let q = Message::Quit;
    let m = Message::Move { x: 12, y: 12 };
    let w = Message::Write(String::from("Hello"));
    let c = Mssage::ChangeColor(0, 255, 255);
}

为枚举定义方法

rust">enum Message {
    Quit,
    Move { x: i32, y: i32 }, //匿名结构体
    Write(String),
    ChangeColor(i32, i32, i32),
}
impl Message {
    fn call(&self) {
        println!("这是call方法"); //这是call方法
    }
}
fn main() {
    let q = Message::Quit;
    let m = Message::Move { x: 12, y: 12 };
    let w = Message::Write(String::from("Hello"));
    let c = Message::ChangeColor(0, 255, 255);
    m.call();
}

Option 枚举

Option 枚举类型来表示可能具有值或者可能没有值

  • Rust 并没有空值,不过它拥有一个可以编码存在或不存在概念的枚举
  • Rust强制您在使用可能为空的值时进行显式处理,以防止出现空值错误(Null Pointer Errors)或空值引起的其他问题
rust">enum Option<T> {
    None,//包含在prelude中,可以直接使用
    Some(T),//包含在prelude中,可以直接使用
}

Some代表可能有值,可能没值
None代表没有值

rust">fn main() {
    let some_string = Some(5);//`Option<i32>` 类型的变量
    let some_string = Some("A String");//`Option<&str>` 类型的变量
    let absent_number: Option<i32> = None;//`Option<i32>` 类型的空变量,变量不包含具体的值
}
  • 要使用Option<T>中的T必须将它转换为T
rust">fn main() {
    let maybe_number: Option<i32> = Some(42);
    // 转换 Option<i32> 到 i32
    let number: i32 = maybe_number.unwrap();//尝试从 `Some` 变体中提取值,并返回该值。如果`Option`是 `None` 变体,`unwrap()`方法会产生panic(崩溃)
    println!("{}", number);//42
}

标准库类型

Vector类型 动态数组

声明Vector

rust">fn main() {
    let v1: Vec<i32> = Vec::new();
    //vec!是一个宏
    let v2 = vec![1, 2, 3];
}

访问元素

rust">fn main() {
    let v = vec![1, 2, 3];
    println!("{:?}", v); //[1, 2, 3],vector没有实现display,所以使用格式化输出
    //索引访问
    println!("{}", &v[0]); //1
    //match get访问
    match v.get(2) {
        Some(third) => println!("{}", third), //3,有值就绑定到返回值third上
        None => println!("没有这个值"),
    }
    //for遍历
    for i in &v{
        println!("{}",i);//123
    }
}

添加删除元素

rust">fn main() {
    let mut v = Vec::new();
    //添加元素
    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    //删除元素
    v.pop();
    println!("{:?}", v); //[1, 2, 3]
}

使用enum在vector中存储不同类型的数据

rust">#[derive(Debug)]
enum SpreadsheetCell {
    Int(i32),
    Folat(f64),
    Text(String),
}
fn main() {
    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Folat(10.12),
    ];
    //for遍历
    for i in &row {
        println!("{:#?}", i); //Int(3,)Text("blue",)Folat(10.12,)
    }
}

String类型 可变字符串

  • String 被存储为由byte(字节)组成的 vector(Vec<u8>),但是不允许索引访问!(UTF-8使用1到4个字节编码Unicode字符,索引访问无法确定字符的边界)
  • UTF-8编码

String类型可获得所有权:OsStringCString

&str字符串切片对String类型的借用:SsStrCStr
声明String

rust">fn main() {
    let s1 = "初始化字符串"; //借用的切片
    let s2 = s1.to_string(); //String类型,由于切片借用不获得所有权,这里实际是&&s1.to_string()
    let s3 = "hello world s3".to_string(); //String类型
    let s4 = String::from("hello world s4"); //String类型
    println!("{},{},{},{}", s1, s2, s3, s4); //初始化字符串,初始化字符串,hello world s3,hello world s4
}

更新String

rust">fn main() {
    let mut s1 = String::from("张");
    //将字符串切片附加到String
    s1.push_str("三");
    println!("{}", s1); //张三
                        //将单个字符附加到String,注意字符是''
    s1.push('🥹');
    println!("{}", s1); //张三🥹
    //拼接字符串
    let s2 = String::from("李四");

    //+的实现:pub fn add(self, rhs: Rhs) -> Self::Output
    let s3 = s1 + &s2; //add函数取得s1所有权并附加s2,然后将s1所有权move到s3,s1失效,s2是借用,不改变所有权
    println!("{}", s2); //张三🥹李四

    //format!宏会返回字符串
    let s4 = format!("{}-{}", s2, s3);
    println!("{}", s4); //李四-张三🥹李四
}

切割String

切片

rust">fn main(){
    let s1 = "hello world";
    let s1 = &s1[1..4];
    println!("{}",s1);//hell
}

对于字符编码会不一致的字符串,rust无法推断字符长度,要谨慎操作,以下代码会发生panic,6无法确定🐕的边界

rust">fn main(){
    let s1 = "hello🐕🦊";
    let s1 = &s1[0..6];
    println!("{}",s1);//hell
}

HashMap集合 哈希表

key:value存储数据

  • HashMap不在prelude中,需要use导入
  • HashMap是同构的,所有的key必须是同一类型,所有的value必须是同一类型
  • 每个key只能对应一个value

声明HashMap

rust">use std::collections::HashMap;
fn main() {
    let mut scores: HashMap<String, i32> = HashMap::new();
    scores.insert(String::from("blue"), 10);
    scores.insert(String::from("blue"), 50);
}

访问

rust">use std::collections::HashMap;
fn main() {
    let mut map: HashMap<String, i32> = HashMap::new();
    map.insert(String::from("blue"), 10);
    map.insert(String::from("red"), 50);

    let key = String::from("blue");
    let value = map.get(&key);
    match value{
        Some(s)=>println!("{}",s),//10
        _=>println!("不存在!"),
    }

    for(k,v)in &map{
        println!("{}:{}",k,v);//blue:10 red:50
    }
}

更新HashMap

rust">use std::collections::HashMap;
fn main() {
    let mut map1: HashMap<String, i32> = HashMap::new();
    map1.insert(String::from("blue"), 10);
    map1.insert(String::from("blue"), 50);
    for (k, v) in &map1 {
        println!("{}:{}", k, v); //blue:50
    }
    println!("******************");
    //使用entry判断key是否存在,存在则不更新并返回对应的可变引用,不存在则更新并返回对应的可变应用
    let mut map2 = map1.clone();
    map2.entry(String::from("blue")).or_insert(40);
    map2.entry(String::from("red")).or_insert(60);
    for (k, v) in &map2 {
        println!("{}:{}", k, v); //red:60 blue:50
    }
}

例子

rust">use std::collections::HashMap;
fn main() {
    let text = "hello world wonderful world";
    let mut map = HashMap::new();
    for word in text.split_whitespace() {
        //以空格分割
        let count = map.entry(word).or_insert(0); //存在则不更新并返回对应的可变引用,不存在则更新并返回对应的可变应用
        *count += 1; //解引用改变value的值
    }
    println!("{:?}", map); //{"wonderful": 1, "hello": 1, "world": 2}
}

泛型

提高代码复用能力,消除类型转换,不影响性能

rust">fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];
    for &item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}
fn main() {
    let number_list = [12, 4, 1, 5, 48];
    let result = largest(&number_list);
    println!("数组中最大的数字:{}", result);

    let char_list = vec!['a', 'S', 'w', 'r'];
    let result = largest(&char_list);
    println!("最大的字符:{}", result);
}

泛型结构体

rust">struct Point<T, U> {
    x: T,
    y: U,
}
fn main() {
    let integer = Point { x: 5, y: 12.54 };
    let float = Point { x: 1.0, y: 4.0 };
}

泛型方法

rust">struct Point<T, U> {
    x: T,
    y: U,
}
impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}
fn main() {
    let p1 = Point { x: 5, y: 4 };
    let p2 = Point {
        x: "Hello",
        y: "World",
    };
    let p3 = p1.mixup(p2);
    println!("混合两点的x、y(x:{},y:{})", p3.x, p3.y); //混合两点的x、y(x:5,y:World)
}

Associated Types 关联类型

在 trait 中定义类型占位符的机制,可以在实现 trait 时具体化

rust">// 定义一个 Container trait,其中包含一个关联类型 Item
trait Container {
    type Item;//占位符,用于表示容器中元素的类型
    fn first(&self) -> Option<&Self::Item>;// 获取容器中的第一个元素的引用
    fn last(&self) -> Option<&Self::Item>;// 获取容器中的最后一个元素的引用
}
// 对 Vec<T> 实现 Container trait
impl<T> Container for Vec<T> {
    type Item = T;//将 Item 关联类型具体化为 T,即 Vec 中元素的类型
    fn first(&self) -> Option<&Self::Item> {
        self.get(0)
    }
    fn last(&self) -> Option<&Self::Item> {
        self.get(self.len() - 1)
    }
}
// 对自定义的容器 MyContainer 实现 Container trait
struct MyContainer<T> {
    elements: Vec<T>,
}
impl<T> Container for MyContainer<T> {
    type Item = T;//将 Item 关联类型具体化为 T
    fn first(&self) -> Option<&Self::Item> {
        self.elements.first()
    }
    fn last(&self) -> Option<&Self::Item> {
        self.elements.last()
    }
}
fn main() {
    let v = vec![1, 2, 3, 4];
    let my_container = MyContainer {
        elements: vec![10, 20, 30, 40],
    };

    // 使用 Vec<T> 实现的 Container trait
    println!("vec第一个元素: {:?}", v.first()); //vec第一个元素: Some(1)
    println!("vec最后一个元素: {:?}", v.last()); //vec最后一个元素: Some(4)

    // 使用 MyContainer 实现的 Container trait
    println!("MyContainer第一个元素: {:?}", my_container.first()); //MyContainer第一个元素: Some(10)
    println!("MyContainer最后一个元素: {:?}", my_container.last()); //MyContainer最后一个元素: Some(40)
}

http://www.niftyadmin.cn/n/5536893.html

相关文章

django admin添加自己的页面

建立模型 如果要单独建一个页面&#xff0c;用于展示model的数据&#xff0c;可以新建一个model&#xff0c;继承自要展示的那个类 class ViewsByDayModel(ViewsByDay): # 父类为要展示的model类class Meta:proxy True # 使用代理verbose_name 每日浏览次数统计verbose_nam…

ChatGPT在Java后端开发中的应用与影响

随着人工智能技术的发展&#xff0c;尤其是OpenAI推出的聊天机器人模型ChatGPT&#xff0c;其强大的自然语言理解和生成能力正在改变着我们的生活和工作方式。在Java后端开发领域&#xff0c;ChatGPT同样有着广泛的应用前景&#xff0c;并且能够为Java后端开发者带来诸多好处。…

Android高级——智能指针

智能指针 智能指针是一种能够自动维护对象引用计数的技术 引用了一个实际使用的对象&#xff0c;而不是一个指针智能指针构造时&#xff0c;增加它所引用的对象的引用计数智能指针析构时&#xff0c;减少它所引用的对象的引用计数 但智能指针无法解决循环引用问题&#xff0…

【项目管理】项目风险管理(Word原件)

风险和机会管理就是在一个项目开发过程中对风险进行识别、跟踪、控制的手段。风险和机会管理提供了对可能出现的风险进行持续评估&#xff0c;确定重要的风险机会以及实施处理的策略的一种规范化的环境。包括识别、分析、制定处理和减缓行动、跟踪 。合理的风险和机会管理应尽力…

三菱PLC 6行程序实现8电机顺序启动逆序停止

目录 概要指令概述顺序启动梯形图逆序停止梯形图 概要 这里主要用到的是三菱的位左移&#xff08;SFTL&#xff09;和右移&#xff08;SFTR&#xff09;指令来实现顺序启动和逆序停止&#xff0c;时间可自由设置&#xff0c;除了应用在电机上&#xff0c;也可以用来做跑马灯。…

有哪些在本地运行大模型的方法

前言 在本文中&#xff0c;我们将看到在本地运行任何 LLM 的不同方法 1/ LMStudio LM Studio 是一款桌面应用程序&#xff0c;用于在计算机上运行本地 LLM。链接&#xff1a;https://lmstudio.ai/ 2/ Ollama Ollama 是一款工具&#xff0c;可让您在机器上本地运行开源大型语…

“拆分盘投资:机遇与风险并存

一、引言 随着互联网技术的日新月异&#xff0c;金融投资领域迎来了前所未有的变革&#xff0c;其中拆分盘作为一种新兴的投资模式&#xff0c;正逐渐进入公众的视野。其独特的价值增长逻辑和创新的投资机制&#xff0c;为投资者开辟了新的财富增值渠道。本文旨在深入探讨拆分…

(论文版)深度学习 | 基于 VGG16-UNet 语义分割模型的猫狗图像提取研究

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本实验本项目基于 VGG16-UNet 架构&#xff0c;利用 Labelme 标注数据和迁移学习&#xff0c;构建高效准确的猫狗图像分割模型。通过编码器-解码器结构&#xff08;特征提取-上采样&#xff09;提升分割精度&#xff0c;适应不同…