保健品做哪个网站好,许昌企业网站去哪开发,sem竞价推广代运营,昆山市建设工程质量检测中心网站【rCore OS 开源操作系统】Rust 语法详解: Strings
前言
这次涉及到的题目相对来说比较有深度#xff0c;涉及到 Rust 新手们容易困惑的点。
这一次在直接开始做题之前#xff0c;先来学习下字符串相关的知识。
Rust 的字符串
Rust中“字符串”这个概念涉及多种类型涉及到 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(wowamazing);
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! Theres 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( Whats up!), Whats 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。 这里我根据题目的提示查阅了官方文档 然后还要注意有的方法挂在是字符串切片有的则挂在可变字符串上。 所以在操作它们的时候还得先转化。
// 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( Whats up!), Whats 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);}
}