Day2用 rustlings 练习 Rust 语言-Move Semantics

大家好

今天 完成 2024年自动驾驶OS开发训练营-初阶营第四期-导学

Day2用 rustlings 练习 Rust 语言 -Move Semantics

alt
alt
alt

https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html

提交代码时候 提示 没有权限怎么出来

alt
alt

aciton

alt

参考开发环境配置

https://rcore-os.cn/arceos-tutorial-book/ch01-02.html

我的题目

https://github.com/cicvedu/rustlings-semester-4-watchpoints

创建ssh key,用于ssh方式克隆github代码。 在linux环境下,使用ssh-keygen -t rsa -b 4096 -C "你的邮箱"命令,创建ssh key, 下面的选项全部直接敲回车即可。 随后使用 cat ~/.ssh/id_rsa.pub

Primitive Types

Rust has a couple of basic types that are directly implemented into the compiler. In this section, we'll go through the most important ones.

Further information

  • Data Types
  • The Slice Type
alt

The Slice Type Slices let you reference a contiguous sequence of elements in a collection rather than the whole collection.

A slice is a kind of reference, so it does not have ownership.

alt
alt

在 Rust 中,切片(slice)是从数组或另一个切片中引用一系列连续元素的视图。要创建一个切片,你需要指定切片的开始和结束位置(不包含结束位置的索引)。在数组 a 中,如果你想得到 [2, 3, 4] 这个切片,你需要从索引 1 开始,到索引 4 结束(不包含索引 4)。

下面是如何修复你的测试代码:

#[test]
fn slice_out_of_array() {
    let a = [12345];

    // 从索引 1 开始,到索引 4 结束的切片
    let nice_slice = &a[1..4];

    assert_eq!([234], nice_slice);
}

在这个例子中,&a[1..4] 创建了一个从数组 a 中索引 1 开始到索引 3 结束的切片,因为 Rust 的切片语法是左闭右开区间(包含开始,不包含结束)。这样 nice_slice 就包含了数组 a 中的 [2, 3, 4]

在命令行输入rustlings watch 开始编辑代码的循环实验

alt

Understanding Ownership

Ownership is Rust’s most unique feature and has deep implications for the rest of the language.

It enables Rust to make memory safety guarantees without needing a garbage collecto

What Is Ownership?

alt

Ownership Rules First, let’s take a look at the ownership rules. Keep these rules in mind as we work through the examples that illustrate them:

  • Each value in Rust has an owner.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value will be dropped

alt
alt

代码示例本身是正确的,并且展示了 Rust 中所有权和复制的概念。但是,如果您想要确保代码能够编译并运行,并且想要满足一些可能的改进或更正,这里有一些建议:

  1. 确保 takes_ownershipmakes_copy 函数在 main 函数之前定义,因为 Rust 中的函数需要先声明后使用。

  2. 添加注释,说明为什么 stakes_ownership 调用后不能被使用,而 xmakes_copy 调用后仍然可以被使用。

  3. 添加 main 函数的返回类型,虽然在简单的程序中这不是必需的,但这是一个好的编程习惯。

  4. 使用 Rust 的格式化工具,比如 rustfmt,来保持代码的整洁。

下面是根据上述建议修改后的代码:

fn takes_ownership(some_string: String) { // 函数定义在 main 之前
    println!("{}", some_string);
// some_string 的作用域结束,调用 Drop

fn makes_copy(some_integer: i32) { // 函数定义在 main 之前
    println!("{}", some_integer);
// some_integer 的作用域结束,没有调用 Drop,因为 i32 是 Copy 类型

fn main() -> () { // 明确 main 函数的返回类型为 ()
    let s = String::from("hello");  // s 拥有 "hello" 的所有权

    takes_ownership(s);             // s 的值移动到 takes_ownership 函数

    // 下面的代码尝试使用 s 将会导致编译错误,因为 s 的值已经移动
    // let len = s.len(); // 错误:s 已移动

    let x = 5;                      // x 包含值 5

    makes_copy(x);                  // x 的值被复制到 makes_copy 函数
                                    // x 仍然有效,因为 i32 是 Copy 类型

    // x 仍然可以使用
    println!("x is {}", x);
}

在这个修改后的版本中,我们添加了 main 函数的返回类型 (),这表示 main 函数不返回任何值。同时,注释被添加来解释为什么 stakes_ownership 调用后不能被使用,而 xmakes_copy 调用后仍然有效。此外,我们还展示了尝试在 takes_ownership 调用后使用 s 会导致编译错误的例子,以及 xmakes_copy 调用后仍然可以使用的例子。

Vectors

Vectors are one of the most-used Rust data structures.

In other programminglanguages, they'd simply be called Arrays, but since Rust operates on a bit of a lower level, an array in Rust is stored on the stack (meaning it can't grow or shrink, and the size needs to be known at compile time), and a Vector is stored in the heap (where these restrictions do not apply).

Vectors are a bit of a later chapter in the book, but we think that they're useful enough to talk about them a bit earlier. We shall be talking about the other useful data structure, hash maps, later.

Further information

  • Storing Lists of Values with Vectors
  • iter_mut
  • map

alt vec_map 函数的作用是接受一个 Vec<i32> 类型的引用(即一个包含 32 位整数的向量),然后返回一个新的 Vec<i32>,这个新向量中的每个元素都是原向量中对应元素的两倍。

具体来说,vec_map 函数中的 mapcollect 方法是这样工作的:

  1. **v.iter()**:这个方法创建了一个迭代器,它遍历 v 向量的每个元素。iter 方法返回的迭代器提供的是向量中元素的不可变引用。

  2. **.map(|element| { element * 2 })**:map 方法接受一个闭包(匿名函数),在这个例子中,闭包接受一个参数 element(向量中的一个元素的不可变引用),然后返回这个元素值乘以 2 的结果。闭包体内的操作 element * 2 实际上是在对引用指向的数据进行解引用(通过 * 操作符)并执行乘法操作。

  3. **.collect()**:map 方法返回的是一个惰性迭代器,它逐个应用闭包中的操作,但不会立即收集结果。collect 方法被调用来将这些经过 map 处理的元素收集到一个新的 Vec<i32> 向量中。

使用 mapcollect 的好处是,它们允许你以一种声明性的方式对集合中的每个元素执行操作,并将结果收集到新的集合中,而不需要编写显式的循环。这种方式代码更简洁,也更符合 Rust 的风格。

这里是一个如何使用 vec_map 函数的示例:

fn main() {
    let original_vec = vec![1234];
    let doubled_vec = vec_map(&original_vec);
    println!("{:?}", doubled_vec); // 这将打印:[2, 4, 6, 8]
}

在这个示例中,vec_map 接收 original_vec 的引用,创建了一个新的向量 doubled_vec,其中包含了原向量每个元素的两倍值,并打印出来。

Move Semantics

These exercises are adapted from pnkfelix's Rust Tutorial -- Thank you Felix!!!

Further information

For this section, the book links are especially important.

  • Ownership
  • Reference and borrowing

move_semantics1.rs

alt

move_semantics2.rs

alt
alt

// move_semantics5.rs

alt

Rust 中的可变引用有一条规则:在任意给定时间,你可以拥有任意数量的不可变引用,或者至多一个可变引用。这条规则确保了内存安全,防止了数据竞争。

在提供的代码中,存在一个问题:main 函数试图创建两个可变引用 yz,都指向同一个变量 x。这是不允许的,因为 Rust 的借用规则不允许在同一作用域内对同一变量有多个可变引用。这就是为什么代码无法编译的原因。

要修复这个问题,你需要确保在任何给定时间,只有一个可变引用存在。这里是修复后的代码:

fn main() {
    let mut x = 100;
    {
        let y = &mut x;
        *y += 100// 此时 x 的值变为 200
    } // 'y' 的作用域结束,可变引用被销毁
    {
        let z = &mut x; // 可以创建新的可变引用,因为 'y' 已经不存在了
        *z += 1000// 此时 x 的值变为 1200
    } // 'z' 的作用域结束,可变引用被销毁
    assert_eq!(x, 1200); // 断言 x 的值是 1200,这是正确的
}

在这个修复的版本中,我们通过创建内部作用域来确保在任何时候只有一个可变引用存在。首先,我们创建了 y 的作用域,对其进行了操作,然后这个作用域结束,y 不再有效。之后,我们创建了 z 的作用域,再次对 x 进行操作。这样就遵守了 Rust 的借用规则,使得代码可以编译并按预期运行。

alt
alt
alt

这段编译错误信息指出了 Rust 代码中的一个生命周期问题。问题出在 string_uppercase 函数的实现上,它试图将一个临时值赋给一个引用,这是不允许的。

这里是出错的代码行:

data = &data.to_uppercase();

在这行代码中,data.to_uppercase() 创建了一个 String 的新实例,这个实例是一个临时值,它的生命周期依赖于 data 的借用。然而,尝试将这个临时值的引用赋给 data 是不合法的,因为临时值会在语句结束时立即被销毁,而 data 需要一个比临时值更长的生命周期。

要修复这个问题,我们需要修改 string_uppercase 函数,让它接受一个可变引用,并且直接在该引用指向的数据上调用 make_uppercase() 方法,而不是尝试重新赋值。这里是修复后的代码:

fn string_uppercase(data: &mut String) {
    data.make_uppercase(); // 直接在 data 上调用 make_uppercase 方法

    println!("{}", data);
}

在这个修复版本中,我们移除了 mut data: &String 中的 mut,因为 data 已经是一个可变引用。然后我们直接在 data 上调用 make_uppercase(),这样就不会有临时值的问题。make_uppercase() 方法会修改 data 引用指向的 String 实例,而不需要创建新的 String

此外,main 函数中的调用也需要相应地更新,以传递一个可变引用:

fn main() {
    let mut data = "Rust is great!".to_string();

    string_uppercase(&mut data); // 传递一个可变引用
    println!("{}", data); // 打印修改后的字符串
}

现在,string_uppercase 函数接受 data 的可变引用,直接修改它,并且 main 函数中的 data 是可变的,可以被 string_uppercase 所修改。这样代码就可以编译并按预期工作了。

alt
alt
alt
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
    1. 高级后端工程师,擅长c++并发编程。
    2. 专注分布式存储,分布式数据库。
    3. 时间的践行者,立志成为一名讲师。
【我的成绩】
    1.  为了走出农村,2次高考
         一次考研失败,
         遇挫之后不知道干什么,开启被动之旅。
    2. 为了找到合适工作,   
        深入研究c++书籍和leetcode 200题目
    3. 为了提高项目能力,参与开源项目建设。
    4. 为了把简单事情说清楚/要干啥
        按照《只管去做》,《福格行为模型>>方法。
        纸上得来终觉浅,绝知此事要躬行
        做一个践行者。
【我能提供】
    1.  后端程序员的简历优化+就业辅导+职业规划
    2.  全栈工程师(c++,rust,go,python )项目开发
    3. 一年践行12本书践行记录。
【希望一起解决什么,开启破圈之旅】
    1. 交接更多朋友,抱团取暖。
        寻找意义本身就更加有意义。
    2. 无法做整个系统,聚焦一个模块
         道可道也,非恒道也 
         名可名也,非恒名也。
         无名 万物之始也
         有名 万物之母也
         别想太多,只管去做,躬身入局
     
链接我: # + v(github):watchpoints   
        #众号:后端开发成长指南
**/

本文由 mdnice 多平台发布

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

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

相关文章

图片管理新纪元:高效批量横向拼接图片,一键生成灰色艺术效果,打造专业视觉体验!

在数字时代&#xff0c;图片已成为我们生活和工作中不可或缺的一部分。但面对海量的图片&#xff0c;如何高效地进行批量管理、拼接和调色&#xff0c;成为许多人面临的难题。今天&#xff0c;我们为您带来了一款颠覆性的图片管理工具&#xff0c;让您轻松实现图片批量横向拼接…

智慧生活新篇章,Vatee万腾平台领航前行

在21世纪的科技浪潮中&#xff0c;智慧生活已不再是一个遥远的梦想&#xff0c;而是正逐步成为我们日常生活的现实。从智能家居的温馨便捷&#xff0c;到智慧城市的高效运转&#xff0c;科技的每一次进步都在为我们的生活增添新的色彩。而在这场智慧生活的变革中&#xff0c;Va…

论文翻译 | (TAKE A STEP BACK) 后退一步:在大型语言模型中通过抽象来调用推理

摘要 我们介绍了STEP-BACK提示&#xff0c;这是一种简单的提示技术&#xff0c;使LLM能够进行抽象&#xff0c;从而从包含特定细节的实例中派生高级概念和第一原则。使用概念和原则来指导推理&#xff0c;LLM显着提高了他们遵循正确推理路径的能力。我们使用PaLM-2L、GPT-4和Ll…

Redis数据结构解析-RedisObject

文章目录 ☃️概述☃️源码 ☃️概述 RedisObject 是 Redis 中表示数据对象的结构体&#xff0c;它是 Redis 数据库中的基本数据类型的抽象。在 Redis 中&#xff0c;所有的数据都被存储为 RedisObject 类型的对象。 RedisObject 结构体定义如下&#xff08;简化版本&#xf…

kafka中

Kafka RocketMQ概述 RabbitMQ概述 ActiveMQ概述 ZeroMQ概述 MQ对比选型 适用场景-从公司基础建设力量角度出发 适用场景-从业务场景出发 Kafka配置介绍 运行Kafka 安装ELAK 配置EFAK EFAK界面 KAFKA常用术语 Kafka常用指令 Kafka中消息读取 单播消息 group.id 相同 多播消息 g…

MyBatis-Plus-实用的功能自动填充字段

前言: java项目用到了mybatis-plus&#xff0c;在一些类里面需要在更新时候&#xff0c;统一设置&#xff0c;修改人&#xff0c;修改ID&#xff0c;修改时间。新增时候设置 创建人&#xff0c;创建时间等 基础类&#xff1a; Data public abstract class BaseModel implements…

java 公共字段填充

公共字段填充 1、mybatis-plus2、mybatis 使用注解加aop2.1 自定义注解2.2 自定义切面类2.3 在mapper上添加上自定义的注解 1、mybatis-plus 通过在类上使用如下的注解 TableField(fill FieldFill.INSERT) 是 MyBatis-Plus 中的注解&#xff0c;用于自动填充字段的值。MyBat…

简单且循序渐进地查找软件中Bug的实用方法

“Bug”这个词常常让许多开发者感到头疼。即使是经验丰富、技术娴熟的开发人员在开发过程中也难以避免遭遇到 Bug。 软件中的故障会让程序员感到挫败。我相信在你的软件开发生涯中&#xff0c;也曾遇到过一些难以排查的问题。软件中的错误可能会导致项目无法按时交付。因此&…

Linux进程、线程——保姆级助理解

目录 1、进程&#xff08;Process&#xff09; 1.1 进程基本概念&#xff1a; 1.2 进程分类 1.3 进程的特征 1.4 进程和程序的区别 1.5 进程的状态 1.6 进程的创建——Fork()函数 1.6.1 简介 1.6.2 使用 1.7 进程终止 2、线程&#xff08;Thread&#xff09; 1.1 线…

Git管理源代码、git简介,工作区、暂存区和仓库区,git远程仓库github,创建远程仓库、配置SSH,克隆项目

学习目标 能够说出git的作用和管理源代码的特点能够如何创建git仓库并添加忽略文件能够使用add、commit、push、pull等命令实现源代码管理能够使用github远程仓库托管源代码能够说出代码冲突原因和解决办法能够说出 git 标签的作用能够使用使用git实现分支创建&#xff0c;合并…

排序 -- 冒泡排序和快速排序

一、 交换排序 1、基本思想 所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 2、常见的交换排序 1、冒泡…

《征服数据结构》SparseArray

摘要&#xff1a; 1&#xff0c;SparseArray的介绍 2&#xff0c;SparseArray的代码实现 1&#xff0c;SparseArray的介绍 前面我们讲过《ArrayMap》&#xff0c;用它来实现哈希表&#xff0c;其中存放key和value的数组长度是存放散列表数组长度的二倍。 在哈希表中如果key值是…

【Python】已解决:(Python xml库 import xml.dom.minidom导包报错)‘No module named dom’

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;&#xff08;Python xml库 import xml.dom.minidom导包报错&#xff09;‘No module named dom’ 一、分析问题背景 在使用Python处理XML文件时&#xff0c;xml…

中科曙光:新智生产力引擎,是一台精密的AI发动机

每一个时代的新生产力释放&#xff0c;都需要新的发动机来释放新动能。比如蒸汽机之于畜力、燃油机之于蒸汽机&#xff0c;发动机的每一次进化&#xff0c;都为新兴工业体系奠定了更强大的生产力底座。 如今&#xff0c;AI作为新质生产力的关键引擎&#xff0c;带来了史无前例的…

240706_昇思学习打卡-Day18-基于MindSpore的GPT2文本摘要

240706_昇思学习打卡-Day18-基于MindSpore的GPT2文本摘要 今天做一个根据一段文章提取摘要的提取器&#xff0c;基于nlpcc2017摘要数据&#xff0c;内容为新闻正文及其摘要&#xff0c;就是训练集及标签。 首先我们来预装以下MindSpore环境 %%capture captured_output # 实验…

LabVIEW干涉仪测向系统

开发了一套基于LabVIEW的软件系统&#xff0c;结合硬件设备&#xff0c;构建一个干涉仪测向实验教学平台。该平台应用于信号处理课程&#xff0c;帮助学生将理论知识与实际应用相结合&#xff0c;深化对信号处理核心概念的理解和应用。 项目背景&#xff1a; 当前信号处理教学…

昇思25天学习打卡营第十四天|Pix2Pix实现图像转换

训练营进入第十四天&#xff0c;今天学的内容是Pix2Pix图像转换&#xff0c;记录一下学习内容&#xff1a; Pix2Pix概述 Pix2Pix是基于条件生成对抗网络&#xff08;cGAN, Condition Generative Adversarial Networks &#xff09;实现的一种深度学习图像转换模型&#xff0c…

为RK3568或RK3288开发板创建交叉编译环境{采用amd64的ubuntu系统配置交叉编译arm64开发环境}(保姆级包括安装QT)超详细记录版

为RK3568或RK3288开发板创建交叉编译环境{采用amd64的ubuntu系统配置交叉编译arm64开发环境}【保姆级包括安装QT】超详细记录版 Chapter1 为RK3568或RK3288开发板创建交叉编译环境{采用amd64的ubuntu系统配置交叉编译arm64开发环境}(保姆级包括安装QT)超详细记录版一. 安装QT程…

picgo+gitee图床配置

node.js安装 刚开始顺着picgo操作,直接跳转到了node.js官网 下载的时候直接 Next,然后可以自定义安装路径,我的安装路径是C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Node.js 然后再在安装路径的根目录下新建两个文件夹,nodecache 和 nodeglobal, 如图所示:…

C++(Qt)-GIS开发-简易瓦片地图下载器

Qt-GIS开发-简易瓦片地图下载器 文章目录 Qt-GIS开发-简易瓦片地图下载器1、概述2、安装openssl3、实现效果4、主要代码4.1 算法函数4.2 瓦片地图下载url拼接4.3 多线程下载 5、源码地址6、参考 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;GIS开发 …