当前位置: 首页 > article >正文

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

今天是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.kler.cn/a/375018.html

相关文章:

  • C++--------效率和表示
  • 【更新】Docker新手入门教程2:在Windows系统通过compose创建多个mysql镜像并配置应用
  • python fastapi docs UI 失效解决方案
  • GoFrame框架介绍
  • 代码随想录Day37 动态规划:完全背包理论基础,518.零钱兑换II,本周小结动态规划,377. 组合总和 Ⅳ,70. 爬楼梯(进阶版)。
  • vue 基础学习
  • 基于Matlab PCA人脸识别
  • 信息安全入门——网络安全控制
  • 人机环境系统智能是东方天地人思想与西方科技思维的融合
  • Red Hat下载ISO镜像的方法
  • 软中端,硬中断(学习笔记)
  • uicc.hci.service的理解
  • 基于java+SpringBoot+Vue的“衣依”服装销售平台设计与实现
  • 初阶数据结构之顺序表的实现
  • tkinter 走进现代化【一】 - 登录页
  • 从 classList 到 DOMTokenList: 简化类名管理的工具
  • git入门教程11:git安全性
  • 2024年【制冷与空调设备安装修理】考试总结及制冷与空调设备安装修理作业模拟考试
  • 【SSH访问Termux】
  • 时间序列算法---ARIMA
  • 推荐一款功能强大的媒体播放管理:Zoom Player MAX
  • BERT的中文问答系统26
  • 20241101编译Rockchip原厂的RK3566平台的Buildroot【使用荣品的DTS】
  • 91.【C语言】数据结构之单向链表的头删和尾删
  • MySQL 日志之 binlog 格式 → 关于 MySQL 默认隔离级别的探讨
  • 如何实现图片懒加载,原生 + React 实现方式