【rCore OS 开源操作系统】Rust 字符串(可变字符串String与字符串切片str)

【rCore OS 开源操作系统】Rust 语法详解: Strings

前言

这次涉及到的题目相对来说比较有深度,涉及到 Rust 新手们容易困惑的点。

这一次在直接开始做题之前,先来学习下字符串相关的知识。

Rust 的字符串

Rust中“字符串”这个概念涉及多种类型,这里介绍题目中涉及到的两种的字符串类型:&str(字符串切片,slice)和String(可变字符串)。

String 可变字符串

存储在堆中,并且是可变的——是和其他大部分主流编程语言类似的概念。

示例:

let mut s: String = String::from("hello");
s.push_str(", world"); // “hello, world”,是的这里就是可变的

&str 字符串切片

那么,什么是切片呢?

既然 String 被我们称为可变字符串,这里也就暗示字符串切片是不可变的immutable)。

同时,它是存储在栈中的。

来看看如何产生字符串切片:

// 字面量是一种切片
let s1 = "Hello, World"; 
// 完整的写法其实是 let s1: &str = "Hello, World"; // 也可以从可变字符串中切割
let string:String = String::from("wow,amazing");  
let s2 = string[0..3]; // 左开右闭,正好就是 “wow”

可以从切片中得到可变字符串:

let string1 = String::from("hello");
let string2 = "hello".to_string();

这里也不很啰嗦,很直观地就认识了两种字符串在形式上的区别。

那再来看看本质。

所有权、引用与借用

要搞懂字符串的本质,还得回到所有权、引用和借用三个概念上。

所有权

这里是一段官话:

所有权是 Rust 中的核心概念之一,它决定了数据的生命周期和内存管理方式。每个值在 Rust 中都有一个拥有它的变量,称为“所有者”。

所有权有三个特性:

  • 唯一所有者:一个值在同一时间内只能有一个所有者。
  • 所有权转移:当把一个所有者的值传递给另一个变量时,所有权会被转移。
  • 自动释放内存:当一个值的所有者离开作用域时,该值所占用的内存会被自动释放

第一次看估计不太理解,但是没关系,直接来对照代码再看一次:

这里就当作是一个代码拟人小故事来看

// 现在变量 s 是 String::from("hello") 的所有者
let s = String::from("hello");
// 直接赋值,现在 String::from("hello") 到了 t 的手中,t 是新的所有者,而 s 不再是了,s 会被释放掉!
// 这里就体现了三个特性,“唯一所有者”,“所有权转移”和“自动释放内存”。
let t = s; 
//  这里会编译失败,因为 s 已经不再有效println!("{}", s); // 报错

所有权的作用是什么?

这个问题有有更广而全面的回答,此处只简单说明最核心的一点

内存安全,所有权机制的存在避免了许多常见的内存错误,如悬空引用双重释放等问题——因为一个引用永远都是有值的,并且同一时刻只有一个指针能够操作值,而且在值指针失效时会自动销毁。

引用和借用

Rust 中的引用是(直接)基于指针实现的,可以看作是别名

而 JavaScript 等语言并不是直接基于指针实现的,而是依靠对象的引用实现的。
当然了,对象的引用的本质其实也还是可以基于指针——所以这里提到了“直接”一词。

基于指针是什么意思呢?

对于 String 类型,它的定义差不多是这样:

struct MyString {ptr: *const u8, // 一个指针len: usize, // 字符串长度, 是当前字符串中字符的数量cap: usize, // 字符串的最大容量,指最多可以容纳多少长度
}

那别名是什么意思呢?

这里我们也拟人地来解释下:

// a 和 b 是两个人,只是名字相同。
let a = 1;
let b = 1;// s 和 r 是同一个人,只是有两个名字
let mut s = String::from("hello");
let r = &s; // r 是 s 的引用

当然,这里的写法中, r 是不可以去修改值的。
如果需要修改,那么要这样写:

let r = &mut s; // r 是 s 的引用

那什么是借用呢?
这里的官话就是:

借用是值,允许使用一个变量的值,而不改变所有权。

其实,借用就是 Rust 的引用的一个特性。

来看下述代码(魔改自《Rust 高级程序设计》):

fn main() {let s1 = String::from("hello");// 传入一个 s1 的引用,不会改变所有权。// 而 s1 的所有权没有转移,就意味着 s1 不会被销毁,在后面可以接着用。let len = calculate_length(&s1); // 使用 s1 不报错呢println!("The length of '{}' is {}.", s1, len);
}fn calculate_length(s: &String) -> usize {s.len()
}

练习题

Strings1

题目
// strings1.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a
// hint.// I AM NOT DONEfn main() {let answer = current_favorite_color();println!("My current favorite color is {}", answer);
}fn current_favorite_color() -> String {"blue"
}
题解

有了上面的解释后,这里做起来就简单一些了。
这里的考点也就是区分可变字符串 String 和字符串切片 &str

// strings1.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a
// hint.fn main() {let answer = current_favorite_color();println!("My current favorite color is {}", answer);
}fn current_favorite_color() -> String {// 两种写法都可以// "blue".to_string()String::from("blue")
}

Strings2

题目
// strings2.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a
// hint.fn main() {let word = String::from("green"); // Try not changing this line :)if is_a_color_word(&word) {println!("That is a color word I know!");} else {println!("That is not a color word I know.");}
}fn is_a_color_word(attempt: &String) -> bool {attempt == "green" || attempt == "blue" || attempt == "red"
}
题解

在上文的字符串的知识点梳理中,其实已经给出了类似的代码了。

// strings2.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a
// hint.fn main() {let word = String::from("green"); // Try not changing this line :)if is_a_color_word(&word) {println!("That is a color word I know!");} else {println!("That is not a color word I know.");}
}fn is_a_color_word(attempt: &String) -> bool {attempt == "green" || attempt == "blue" || attempt == "red"
}

Strings3

题目
// strings3.rs
//
// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a
// hint.// I AM NOT DONEfn trim_me(input: &str) -> String {// TODO: Remove whitespace from both ends of a string!???
}fn compose_me(input: &str) -> String {// TODO: Add " world!" to the string! There's multiple ways to do this!???
}fn replace_me(input: &str) -> String {// TODO: Replace "cars" in the string with "balloons"!???
}#[cfg(test)]
mod tests {use super::*;#[test]fn trim_a_string() {assert_eq!(trim_me("Hello!     "), "Hello!");assert_eq!(trim_me("  What's up!"), "What's up!");assert_eq!(trim_me("   Hola!  "), "Hola!");}#[test]fn compose_a_string() {assert_eq!(compose_me("Hello"), "Hello world!");assert_eq!(compose_me("Goodbye"), "Goodbye world!");}#[test]fn replace_a_string() {assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool");assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons");}
}
题解

这个题目还是有点难度,考察 Rust 常用的字符串操作 API。
这里我根据题目的提示查阅了官方文档:
Rust字符串操作方法: trim
然后还要注意,有的方法挂在是字符串切片,有的则挂在可变字符串上。
所以在操作它们的时候,还得先转化。

// strings3.rs
//
// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a
// hint.fn trim_me(input: &str) -> String {let string = input.to_string();string.trim().to_string()
}fn compose_me(input: &str) -> String {let mut string = input.to_string();// 这里有个坑点是,push_str 改变的是在原来的值上进行修改,而返回值是一个空的元组string.push_str(" world!");string// 还有一种比较奇技淫巧:// format!("{} world!", input)
}fn replace_me(input: &str) -> String {let str = input.replace("cars", "balloons");str.to_string()
}#[cfg(test)]
mod tests {use super::*;#[test]fn trim_a_string() {assert_eq!(trim_me("Hello!     "), "Hello!");assert_eq!(trim_me("  What's up!"), "What's up!");assert_eq!(trim_me("   Hola!  "), "Hola!");}#[test]fn compose_a_string() {assert_eq!(compose_me("Hello"), "Hello world!");assert_eq!(compose_me("Goodbye"), "Goodbye world!");}#[test]fn replace_a_string() {assert_eq!(replace_me("I think cars are cool"),"I think balloons are cool");assert_eq!(replace_me("I love to look at cars"),"I love to look at balloons");}
}

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

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

相关文章

【EXCEL数据处理】000017 案例 Match和Index函数。

前言:哈喽,大家好,今天给大家分享一篇文章!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【EXCEL数据处理】000016 案例 Match和Index函数。使用的软件&#xff…

DenseNet算法:口腔癌识别

本文为为🔗365天深度学习训练营内部文章 原作者:K同学啊 一 DenseNet算法结构 其基本思路与ResNet一致,但是它建立的是前面所有层和后面层的密集连接,它的另一大特色是通过特征在channel上的连接来实现特征重用。 二 设计理念 三…

成都跃享未来教育咨询有限公司抖音小店:引领教育咨询新风尚

在数字化浪潮席卷全球的今天,教育咨询行业正经历着前所未有的变革。成都跃享未来教育咨询有限公司,作为教育行业的一颗璀璨新星,凭借其前瞻性的教育理念与创新的运营模式,在抖音平台上开设了小店,不仅为广大学子及家长…

学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)

在线学籍管理平台系统 目录 基于SpringbootVUE的在线学籍管理平台系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…

C++多态、虚函数以及抽象类

目录 1.多态的概念 2.多态的定义及实现 2.1多态的构成条件 2.1.1实现多态还有两个必要条件 2.1.2虚函数 2.1.3虚函数的重写/覆盖 2.1.4多态场景的题目 2.1.5虚函数重写的一些其他问题 2.1.5.1协变(了解) 2.1.5.2析构函数的重写 2.1.6override和final关键字 2.…

【Springer上传手稿记录】《Signal, Image and Video Processing》

Springer上传手稿记录 以signal,image and video proecessing为例上传手稿或图片时提示上传失败无法编译成pdf错误1:出现Unknown theoremstyle相关错误错误2:command Illegal错误3:command I found no style file 通用问题问题1&a…

CORE MVC 过滤器 (筛选器)《2》 TypeFilter、ServiceFilter

TypeFilter、ServiceFilter ServiceFilter vs TypeFilter ServiceFilter和TypeFilter都实现了IFilterFactory ServiceFilter需要对自定义的Filter进行注册,TypeFilter不需要 ServiceFilter的Filter生命周期源自于您如何注册(全局、区域)&…

【AI学习】Mamba学习(二):线性注意力

上一篇《Mamba学习(一):总体架构》提到,Transformer 模型的主要缺点是:自注意力机制的计算量会随着上下文长度的增加呈平方级增长。所以,许多次二次时间架构(指一个函数或算法的增长速度小于二次…

SpringBoot框架下校园资料库的构建与优化

1系统概述 1.1 研究背景 如今互联网高速发展,网络遍布全球,通过互联网发布的消息能快而方便的传播到世界每个角落,并且互联网上能传播的信息也很广,比如文字、图片、声音、视频等。从而,这种种好处使得互联网成了信息传…

10.5今日错题解析(软考)

目录 前言面向对象技术——设计模式的应用场景计算机组成与体系结构——逻辑运算 前言 这是用来记录我备考软考设计师的错题的,今天知识点为设计模式的应用场景、逻辑运算,大部分错题摘自希赛中的题目,但相关解析是原创,有自己的…

【Python】Dejavu:Python 音频指纹识别库详解

Dejavu 是一个基于 Python 实现的开源音频指纹识别库,主要用于音频文件的识别和匹配。它通过生成音频文件的唯一“指纹”并将其存储在数据库中,来实现音频的快速匹配。Dejavu 的主要应用场景包括识别音乐、歌曲匹配、版权管理等。 ⭕️宇宙起点 &#x1…

class 004 选择 冒泡 插入排序

我感觉这个真是没有什么好讲的, 这个是比较简单的, 感觉没有什么必要写一篇博客, 而且这个这么简单的排序问题肯定有人已经有写好的帖子了, 肯定写的比我好, 所以我推荐大家直接去看“左程云”老师的讲解就很好了, 一定是能看懂的, 要是用文字形式再写一遍, 反而有点画蛇添足了…

windows下安装rabbitMQ并开通管理界面和允许远程访问

如题,在windows下安装一个rabbitMQ server;然后用浏览器访问其管理界面;由于rabbitMQ的默认账号guest默认只能本机访问,因此需要设置允许其他机器远程访问。这跟mysql的思路很像,默认只能本地访问,要远程访…

Oracle架构之表空间详解

文章目录 1 表空间介绍1.1 简介1.2 表空间分类1.2.1 SYSTEM 表空间1.2.2 SYSAUX 表空间1.2.3 UNDO 表空间1.2.4 USERS 表空间 1.3 表空间字典与本地管理1.3.1 字典管理表空间(Dictionary Management Tablespace,DMT)1.3.2 本地管理方式的表空…

计算机网络(十) —— IP协议详解,理解运营商和全球网络

目录 一,关于IP 1.1 什么是IP协议 1.2 前置认识 二,IP报头字段详解 三,网段划分 3.1 IP地址的构成 3.2 网段划分 3.3 子网划分 3.4 IP地址不足问题 四,公网IP和私有IP 五,理解运营商和全球网络 六&#xff…

基于大数据技术的颈椎病预防交流与数据分析及可视化系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏:Java精选实战项目…

【优选算法】(第二十一篇)

目录 外观数列(medium) 题目解析 讲解算法原理 编写代码 数⻘蛙(medium) 题目解析 讲解算法原理 编写代码 外观数列(medium) 题目解析 1.题目链接:. - 力扣(LeetCode) 2.题目描述 给定⼀个正整数n&#xff0…

算法篇1:双指针思想的运用(1)--C++

一.算法解析 双指针,顾名思义就是两个指针,常见的算法中,我们可以看到两种: 1.对撞指针:一般用于顺序结构,也称为左右指针。 对撞指针从两端向中间移动。一个指针从最左端开始,另一个从最右端…

Yolov8轻量级网络改进GhostNet

1,理论部分 由于内存和计算资源有限,在移动设备上部署卷积神经网络 (CNN) 很困难。我们的目标是通过利用特征图中的冗余,为 CPU 和 GPU 等异构设备设计高效的神经网络,这在神经架构设计中很少被研究。对于类 CPU 设备,我们提出了一种新颖的 CPU 高效 Ghost (C-Ghost) …

Mysql:数据库和表增删查改基本语句

一、数据库操作 1)、数据库创建 创建数据库本质就是创建一个目录(ubuntu,创建的目录文件存放在/var/lib/mysql);后续创建表本质就是在该目录下创建文件(不同存储引擎,会创建的文件数目是不同的…