Rust精简核心笔记:第三波,基础语法完结篇

news2024/11/5 17:12:21

今天是Rust精简核心笔记第三波,也是完结篇。之前已经介绍了二波,Rust精简核心笔记:第一波,深入浅出语法精华-CSDN博客,Rust精简核心笔记:第二波,语法精髓部分解锁-CSDN博客,通过三波分享把Rust的核心语法快速进行掌握,也方便进行知识点回顾和速查的左右。

这些精简语法虽可以快速的掌握核心知识点,但如果深入学习和应用还需要结合项目进行实战和练习(更多最新文章也可关注微信公号:良技漫谈)

Rust精简笔记(三)

  •  第三波主要包括函数&闭包&迭代器、指针&智能指针、引用模块的相关介绍

  • 参考The Rust Programming Language & Rust in Action

十,函数、闭包、迭代器

函数:
  • 函数的定义方式及在结构体实现里关联函数,关联函数与方法的使用区别

use std::primitive;

struct Point {
    x: i32,
    y: i32,
}
impl Point {
    // 关联函数(没有self相关参数)
    fn new(x: i32, y: i32) -> Point {
        Point { x: x, y: y }
    }
    // 方法(参数为&self,是个隐示的,调用时无需传递表明是该类型而已)
    fn get_x(&self) -> i32 {
        self.x
    }
}
fn main() {
    //关联函数使用:: 方法使用类型.方法,如Point::new, point.get_x
    let point = Point::new(5, 6);
    println!("get x={}", point.get_x());
}
闭包:
  •  闭包(closures)是可以保存在一个变量中或作为参数传递给其他函数的匿名函数。闭包的定义以一对竖线(|)开始,在竖线中指定闭包的参数

fn  add_one_v1   (x: u32) -> u32 { x + 1 }  //函数的定义
let add_one_v2 = |x: u32| -> u32 { x + 1 }; // 完整标注的闭包定义
let add_one_v3 = |x|             { x + 1 };  // 闭包定义中省略了类型注解
let add_one_v4 = |x|               x + 1  ;  // 闭包体只有一行,去掉了大括号
  • 闭包会捕获其环境:

  •  可以捕获其环境并访问其被定义的作用域的变量。如下边 x 并不是 equal_to_x 的一个参数,equal_to_x 闭包也被允许使用变量 x,因为它与 equal_to_x 定义于相同的作用域

fn main() {
    let x = 4;
    let equal_to_x = |z| z == x;
    let y = 4;

    assert!(equal_to_x(y));
}
  • 当闭包从环境中捕获一个值,闭包会在闭包体中储存这个值以供使用,这会使用内存并产生额外的开销。

  • 闭包可以通过三种方式捕获其环境,他们直接对应函数的三种获取参数的方式:获取所有权,可变借用和不可变借用。

FnOnce 消费从周围作用域捕获的变量,闭包周围的作用域被称为其 环境,environment。为了消费捕获到的变量,闭包必须获取其所有权并在定义闭包时将其移动进闭包。其名称的 Once 部分代表了闭包不能多次获取相同变量的所有权的事实,所以它只能被调用一次
FnMut 获取可变的借用值所以可以改变其环境
Fn 从其环境获取不可变的借用值

由于所有闭包都可以被调用至少一次,所以所有闭包都实现了 FnOnce .大部分需要指定一个 Fn 系列 trait bound 的时候,可以从 Fn 开始,而编译器会根据闭包体中的情况告诉你是否需要 FnMut 或 FnOnce。

  • 带有泛型和 Fn trait 的闭包: 可以创建一个存放闭包和调用闭包结果的结构体, 目的:结构体只会在需要结果时执行闭包,并会缓存结果值,再次调用闭包可以复用该值.

struct Cacher<T>
where
    T: Fn(u32) -> u32,
{
    calculation: T,
    value: Option<u32>,
}

创建Cache的结构体,泛型T类型使用where 声明类型为闭包,结构体包含一个闭包,和一个用于存放闭包返回的值的u32类型,因为有可能第一次没有缓存,所有使用Option的类型。即可能是some(u32) 或者None

  • 官方完整例子:

use std::thread;
use std::time::Duration;

struct Cacher<T>
where
    T: Fn(u32) -> u32,
{
    calculation: T,
    value: Option<u32>,
}

impl<T> Cacher<T>
where
    T: Fn(u32) -> u32,
{
    fn new(calculation: T) -> Cacher<T> {
        Cacher {
            calculation,
            value: None,
        }
    }

    fn value(&mut self, arg: u32) -> u32 {
        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            }
        }
    }
}

fn generate_workout(intensity: u32, random_number: u32) {
    let mut expensive_result = Cacher::new(|num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    });

    if intensity < 25 {
        println!("Today, do {} pushups!", expensive_result.value(intensity));
        println!("Next, do {} situps!", expensive_result.value(intensity));
    } else {
        if random_number == 3 {
            println!("Take a break today! Remember to stay hydrated!");
        } else {
            println!(
                "Today, run for {} minutes!",
                expensive_result.value(intensity)
            );
        }
    }
}

fn main() {
    let simulated_user_specified_value = 10;
    let simulated_random_number = 7;

    generate_workout(simulated_user_specified_value, simulated_random_number);
}

a.这样可以起到了使用结构体缓存了闭包执行的结果,会先从结构体里查找缓存的值,没有再计算。b.同理也可以改造value的类型为HashMap, 可以通过key来找值,避免返回之前计算的始终同一个值。

iterator:

  • 迭代器(iterator): 负责遍历序列中的每一项和决定序列何时结束的逻辑。

    let v1 = vec![1, 2, 3];
    let v1_iter = v1.iter();
    let total: i32 = v1_iter.sum();
    println!("value = {}", { total })
  •  next 是 Iterator 实现者被要求定义的唯一方法

  let v1 = vec![1, 2, 3];
  let mut v1_iter = v1.iter();
  assert_eq!(v1_iter.next(), Some(&1));
  • 调用 map 方法创建一个新迭代器,接着调用 collect 方法消费新迭代器并创建一个 vector

//next 一次返回迭代器中的一个项,封装在 Some 中,当迭代器结束时,它返回 None
fn main() {
    let v1: Vec<i32> = vec![1, 2, 3];
    let mut newiter = v1.iter().map(|x| x + 1);
    let newVector: Vec<_> = newiter.collect();
    assert_eq!(newVector, vec![2, 3, 4]);
}
  •  迭代器 iter()、iter_mut()、into_iter()区别:

  1.  iter()返回的是值的不可变引用. 即&T

  2.  iter_mut() 返回的是值的可变引用. 即&mut T

  3.  into_iter() 返回的是T类型的值

use core::num;
fn main() {
    // iter() 返回的是值的不可变引用,即&T.(此处map里闭包x本身无法改变)
    let vec = vec![1, 2, 3, 4];
    let new_vec: Vec<_> = vec.iter().map(|x| x + 1).collect();
    println!("{:?}", vec);
    println!("{:?}", new_vec);

    //iter_mut() 返回的是值的可变引用,即&mut T.(此处map里闭包x本身+1)
    let mut vec = vec![1, 2, 3, 4];
    vec.iter_mut().for_each(|x| *x += 1);
    println!("{:?}", vec);

    //into_iter() 返回的是T类型的值  (因为所有权 vec是不能再使用)
    let vec = vec![1, 2, 3, 4];
    let new_vec: Vec<_> = vec.into_iter().filter(|x| *x == 2).collect();
    // println!("{:?}", vec); // 无法编译
    println!("{:?}", new_vec);
}
   
  • 实现Iterator trait 来创建自定义迭代器:

struct Counter {
    count: u32,
}

impl Counter {
    fn new() -> Counter {
        Counter { count: 0 }
    }
}

//Counter 类型实现 Iterator trait,通过定义 next 方法来指定使用迭代器时的行为
impl Iterator for Counter {
    type Item = u32; 
     //将迭代器的关联类型 Item 设置为 u32,意味着迭代器会返回 u32 值集合
    fn next(&mut self) -> Option<Self::Item> {
        if self.count < 5 {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}
  •  Rust里iterator的定义:

pub trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}

十一,指针&智能指针

  • 指针是一个包含内存地址的变量的通用概念, 智能指针(smart pointers)是一类数据结构,他们的表现类似指针,但是也拥有额外的元数据和功能

  •  智能指针通常使用结构体实现,智能指针其实现了 Deref 和 Drop trait(离开作用域时运行的代码)

1. Box 用于在堆上分配值:
let b = Box::new(1);
2. Rc 引用计数智能指针:
  •  Rc

     只能用于单线程场景
   //Rc::clone 只会增加引用计数, 这样a,b都是指向1
    let a = Rc::new(1);
    let b = Rc::clone(&a);
3. RefCell<T> 和内部可变性模式:
  •  RefCell<T> 代表其数据的唯一的所有权, 他具有如下特点:

// 在任意给定时刻,只能拥有一个可变引用或任意数量的不可变引用 之一(而不是两者)。
//引用必须总是有效的。

    let num = 1;
    let r1 = RefCell::new(1);
    // Ref - 只有一个不可变借用
    let r2 = r1.borrow();
    // RefMut - mutable  可变借用
    let r3 = r1.borrow_mut();
    // RefMut - 可变借用
    let r4 = r1.borrow_mut();
  • 内部可变性(Interior mutability): 是Rust 中的一个设计模式,它允许你即使在有不可变引用时也可以改变数据。

  •  实现是通过不可变的Rc<T>, 此时的T的类型为RefCell<T>, 即结合成Rc<RefCell<T>> 来实现内部可变性,而外部是无法修改的。

  • let value = Rc::new(RefCell::new(5)) 完整例子如下:

#[derive(Debug)]
enum List {
    Cons(Rc<RefCell<i32>>, Rc<List>),
    Nil,
}

use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let value = Rc::new(RefCell::new(5));

    let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));

    let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
    let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));

    *value.borrow_mut() += 10;

    println!("a after = {:?}", a);
    println!("b after = {:?}", b);
    println!("c after = {:?}", c);
}

十二,使用和引用模块代码:

  •  模块的创建和引用

fn some_function() {}
mod outer_module {
    // private module
    pub mod inner_module {
        // public module
        pub fn inner_public_function() {
            super::super::some_function();
        }
        fn inner_private_function() {}
    }
}
fn main() {
    // 绝对路径 从 crate 根开始,以 crate 名或者字面值 crate 开头。
    crate::outer_module::inner_module::inner_public_function();
    //  相对路径(relative path)从当前模块开始,以 self、super 或当前模块的标识符开头。
    outer_module::inner_module::inner_public_function();
    // 使用 use 关键字将路径引入作用域
    use outer_module::inner_module;
    inner_module::inner_public_function();
}

连续三波的精简笔记整理完了,这些是比较好的快速学习rust和日常回顾的资料,但这些还只是rust基础。

想要把rust理解和运用熟练,和其他编程语言一样,先写上几万行代码,做几个项目。

PS: 也欢迎大家评论和交流~ 更多文章也可关注微信公号:良技漫谈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何找到车在路上行驶的视频素材

作为一名热爱拍摄视频的大学生&#xff0c;找到合适的车在路上行驶的视频素材是非常重要的。不论你是制作城市宣传片、汽车广告&#xff0c;还是交通相关的教学视频&#xff0c;高质量的视频素材都能显著提升作品的专业性。今天&#xff0c;我为大家推荐几个优秀的网站&#xf…

unity中预制体的移动-旋转-放缩

unity中预制体的移动-旋转-放缩 左上侧竖栏图标介绍Tools(手形工具)Move Tool(移动工具&#xff0c;单位米)Rotate Tool(旋转工具&#xff0c;单位角度)Scale Tool(缩放工具&#xff0c;单位倍数)Rect Tool(矩形工具)Transform Tool(变换工具)图标快捷键对照表工具使用的小技巧…

用Pyhon写一款简单的益智类小游戏——2048

文字版——代码及讲解 代码—— import random# 初始化游戏棋盘 def init_board():return [[0] * 4 for _ in range(4)]# 在棋盘上随机生成一个2或4 def add_new_tile(board):empty_cells [(i, j) for i in range(4) for j in range(4) if board[i][j] 0]if empty_cells:i,…

【UBuntu20 配置usb网卡】 记录Ubuntu20配置usb网卡(特别是建立热点)

【UBuntu20 配置usb网卡】 Ubuntu20配置usb网卡&#xff08;特别是建立热点&#xff09; 一、 闲言碎语的前言 usb的外置网卡&#xff0c;相比Windows即插即用&#xff0c;Linux买回来一顿折腾&#xff0c;准备把过程梳理一下记录起来。 网卡的方案其实就那几家&#xff0c;…

Training-free layout control with cross-attention guidance

https://zhuanlan.zhihu.com/p/666445024https://zhuanlan.zhihu.com/p/666445024 支持两种模式,1.sd文生图;2.绑定了dreambooth和text inversion的图像编辑。 # ------------------ example input ------------------examples &

微信网页授权回调地址放多个参数的方法

https://open.weixin.qq.com/connect/oauth2/authorize?appidAPPID&redirect_uriREDIRECT_URI&response_typecode&scopeSCOPE&stateSTATE#wechat_redirect 跳转后地址 redirect_uri/?codeCODE&stateSTATE。 redirect_uri如果不进行urlencode编码, 跳转后…

Virtuoso使用layout绘制版图、使用Calibre验证DRC和LVS

1 绘制版图 1.1 进入Layout XL 绘制好Schmatic后&#xff0c;在原理图界面点击Launch&#xff0c;点击Layout XL进入版图绘制界面。 1.2 导入元件 1、在Layout XL界面左下角找到Generate All from Source。 2、在Generate Layout界面&#xff0c;选中“Instance”&#…

「Mac畅玩鸿蒙与硬件13」鸿蒙UI组件篇3 - TextInput 组件获取用户输入

在鸿蒙应用开发中,TextInput 组件用于接收用户输入,适用于文本、密码等多种输入类型。本文详细介绍鸿蒙 TextInput 组件的使用方法,包括输入限制、样式设置、事件监听及搜索框应用,帮助你灵活处理鸿蒙应用中的用户输入。 关键词 TextInput 组件用户输入输入限制事件监听搜索…

偷懒总结篇|贪心算法|动态规划|单调栈|图论

由于这周来不及了&#xff0c;先过一遍后面的思路&#xff0c;具体实现等下周再开始详细写。 贪心算法 这个图非常好 122.买卖股票的最佳时机 II(妙&#xff0c;拆分利润) 把利润分解为每天为单位的维度&#xff0c;需要收集每天的正利润就可以&#xff0c;收集正利润的区间…

时序数据分析:时序分割

目录 0 工况的定义 1 Changepoint 2 TreeSplit 3 Autoplait 4 应用示例 5.分析结论 0 工况的定义 工业设备系统在不同的外部条件&#xff08;即工况&#xff09;下&#xff0c;往往有多种运行模式&#xff0c;工业生产也往往会分阶段进行&#xff0c;在不同工况下&…

阿里云开源 AI 应用开发框架:Spring AI Alibaba

作者&#xff1a;刘军&#xff0c;Spring AI Alibaba 发起人&#xff0c;Apache Member 编者按&#xff1a; 6 年前&#xff0c;2018 年 10 月&#xff0c;阿里巴巴开源 Spring Cloud Alibaba&#xff0c;旨在帮助 Java 开发者通过 Spring Cloud 编程模型轻松开发微服务应用。…

一年期免费HTTPS证书:网络安全新选择

HTTPS证书的重要性 HTTPS证书&#xff0c;全称为安全套接字层/传输层安全协议证书&#xff0c;是一种在互联网上建立安全连接的数字证书。它通过公钥加密技术&#xff0c;对网站和用户之间的数据传输进行加密&#xff0c;有效防止数据被窃取或篡改&#xff0c;保障用户信息的安…

网络搜索引擎Shodan(7)完结

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 声明&#xff1a;本文主要用作技术分享&#xff0c;所有内容仅供参考。任何使用或依赖于本文信息所造成的法律后果均与本人无关。请读者自行判断风险&#xff0c;并遵循相关法律法规。 感谢泷…

Web-高校教务考试管理系统

目录 一、前言 1.1 实践目的和要求 1.2 实践项目背景及意义 二、实践内容 2.1 实践过程 2.2 实践内容 2.2.1 项目介绍 2.2.2项目开发环境 2.2.3系统组成与功能 2.2.4 开发工作 2.3 主要成果 三、总结 3.1 个人心得 3.2 其它意见 一、前言 1.1 实践目的和…

顺序表排序相关算法题|负数移到正数前面|奇数移到偶数前面|小于x的数移到大于x的数前面|快排思想(C)

负数移到正数前面 已知顺序表 ( a 1 , … , a n ) (a_{1},\dots,a_{n}) (a1​,…,an​)&#xff0c;每个元素都是整数&#xff0c;把所有值为负数的元素移到全部正数值元素前边 算法思想 快排的前后指针版本 排序|冒泡排序|快速排序|霍尔版本|挖坑版本|前后指针版本|非递归版…

预览 PDF 文档

引言 在现代Web应用中&#xff0c;文件预览功能是非常常见的需求之一。特别是在企业级应用中&#xff0c;用户经常需要查看各种类型的文件&#xff0c;如 PDF、Word、Excel 等。本文将详细介绍如何在Vue项目中实现 PDF 文档的预览功能。 实现原理 后端API 后端需要提供一个…

蚁剑的介绍和使用

蚁剑介绍 蚁剑&#xff08;AntSword&#xff09;是一个开源的跨平台网站管理工具&#xff0c;主要用于渗透测试和安全研究。它提供了一个图形化界面&#xff0c;方便用户管理和操作被攻陷的网站。 安装教程&#xff1a; github官网&#xff1a;https://github.com/AntSwordPro…

AppInventor2能否用网络摄像头画面作为屏幕的背景?

// 视频是否可以作为背景&#xff1f; // 有会员提问&#xff1a;能否用网络摄像头的实时画面作为屏幕的背景&#xff1f;就跟这个一样背景全覆盖&#xff1a; 摄像头画面是一个在线的网站链接视频流。 // 原先思路 // 1、目前原生组件无法直接实现这个功能&#xff0c;屏幕…

DBeaver如何查看ER图

前言 我们在使用DBeaver时&#xff0c;有时候需要查看某张表的ER图&#xff0c;这能帮助我们快速看到表的结构&#xff0c;那么&#xff0c;我们应该如何在DBeaver里面查看ER图呢&#xff1f; 如何查看 首先&#xff0c;我们点击下我们要查看的某张表&#xff0c;鼠标右击一…

pytest高版本兼容test_data[“log“] = _handle_ansi(“\n“.join(logs))错误

一、问题现象&#xff1a; 执行seleniumpytest结束时报: INTERNALERROR> File "D:\workspace\pytestframe\.venv\Lib\site-packages\pytest_html\report_data.py", line 141, in add_test INTERNALERROR> test_data["log"] _handle_ansi(&q…