字符串练习
循环字符、判断长度、match
注意,
rust是没有switch这个关键字的,我们可以使用match来替代。
练习:filter 函数,接收一个字符串参数
遍历里面每个字符
fn filter(html:&str) {
for c in html.chars() {
println!("{}", c)
}
// 输出字符串的长度 如果有中文,每个中文占3个长度
println!("{}", html.len())
}
变量名尽量不要和关键字冲突
判断当前字符串的长度:使用 match
我们约定在 4-10 之间
fn filter(html:&str) {
// 范围表达式
match html.len() {
4..=10 => println!("{}", "ok"),
0..=3 => println!("{}", "太短了"),
_ => println!("{}", "不ok"),
}
}
我们这里使用4..=10表示 4 到 10 之间,_下划线代表默认范围
循环练习
fn filter() {
for i in 1..=10 {
println!("{}", i);
}
}
1..=10代表左闭右闭,打印 1-10 的数,即[1, 10]如果修改成
1..10,则代表左闭右开:[1, 10)
String 的基本堆栈结构
str存在于栈中,性能高。通常以&str的方式引用。有点类似C++中的char*
String分配在堆中,属于RUST标准库提供的功能。可增长、可变、有所有权、UTF-8 编码的字符串类型。
// mod lib; // lib.rs 或者 lib/mod.rs
fn main() {
// 两个字面量
let first_name = String::from("无");
let last_name = String::from("解");
// 初始化的时候进行价值不需要加上 mut 后面进行修改的时候必须加上mut
// 重写的原理也是调用 push_str 所以里面要转换成 &str 类型
let name = first_name + &last_name; // &str &String => &str 自动转化
println!("{}", name);
}
字符串相加必须转换为:&str类型。
String::new()创建一个空字符串
String::from()可以从&str类型去创建字符串
let name = "无解"; // 字面量 &str
let mut name1 = String::new(); // 空字符串
// 改变其值
name1.push_str("无解"); // 需要push &str 类型的进入,此时会报一个无法修改的变量,需要给变量加上 mut 此时变量就可以改了。
println!("{}", name1);
使用String:from初始化的方式
let name = String::from("无解"); // 参数为 &str 类型的
使用 format 宏来初始化
let name = format!("{}{}", first_name, last_name); // 拼接2个字符串
堆基本结构
代码:let name = String::from("abc");在内存角度发生了什么?
栈:
| Name | value |
|---|---|
| Ptr 指针 | |
| len | 3 |
| capacity | 3 |
堆:
| index | value |
|---|---|
| 0 | a |
| 1 | b |
| 2 | c |
堆放内容,栈放地址。堆内存由垃圾处理器管理。
let name = String::from("abc");
println!("长度: {}, 容量: {}", name.len(), name.capacity());
如果在来一个变量赋值一个name
let name = String::from("abc");
let name2 = name;
println!("长度: {}, 容量: {}", name2.len(), name2.capacity());
则会新增一个栈保存
name2,同样指向堆中的存储内容。
打印地址
let name = String::from("abc");
println!("{:p}", name.as_ptr());
{}针对基本类型如:int、&str等,都可以直接打印,他们都有对应的Display方法。如果对象或后面的自定义的struct时,则打印不了。
同样的语言里:PHP 不能使用echo 去打印一个对象,如果要输出,则要实现__toString()方法。
Rust里面主要是Display和Debug方法要实现。
fn main() {
let name = String::from("abc");
println!("{:?}", name.as_ptr()); // ? 会调用 Debug
let name2 = name;
println!("{:p}", name2.as_ptr());
println!("长度: {}, 容量: {}", name2.len(), name2.capacity());
}
0x137e06b90
0x137e06b90
长度: 3, 容量: 3
as_ptr():指向了第一个字节的地址,如果占位符里写了{:?}或者{?p},后面打印的内容必须是指针类型。
Rust 常见的符号
unspecified:Display即{},默认就是调用Display
?:Debug
o:Octal八进制
x:LowerHex十六进制
X:UpperHex
p:Pointer
b:Binary 二进制
所有者、字符串拷贝
let name = String::from("abc");
println!("{:p}", name.as_ptr());
name就是这个字符串"abc"的所有者,而且有且只有一个所有者。不能脚踏两条船。当所有者离开作用域,这个值将被抛弃。
fn main() {
let name = String::from("abc");
println!("{:p}", name.as_ptr());
let you = String::from("abc");
println!("{:p}", you.as_ptr());
}
"案例:同名同姓的变量",完全是可以的,第一个字符指针对应的地址,这里是不一样的
0x149606b90
0x149606ba0
"脚踏两条船"
fn main() {
let name = String::from("abc");
let you = name;
println!("{:p}", name.as_ptr());
println!("{:p}", you.as_ptr());
}
此时name叫”abc“,此时把name的值给了you,我就没有了,就不能调用as_ptr(),这个就不能打印了,name这个变量就已经作废了。这也是所有者有且只有一个。
:::details 解决办法
- 第一种就是上面的定义变量值都是一样的即可,即”同名同姓“的含义。
- 第二种可以使用
name.clone()方法
fn main() {
let name = String::from("abc");
let you = name.clone();
println!("{:p}", name.as_ptr());
println!("{:p}", you.as_ptr());
}
就好比是复制了一块内存。
- 第三种:添加
&符号
fn main() {
let name = String::from("abc");
let you = &name;
println!("{:p}", name.as_ptr());
println!("{:p}", you.as_ptr());
}
这 2 个地址是一样的,这个代码没有发生所有者的改变,只是引用。
:::
如果是&str类型,就不会发生所有者转换的问题。
函数传参所有者转移、修改原字符串
所有者转移
fn show_len(s: String) {
println!("{}", s.len());
} // show_len 函数执行完 s 才废掉
fn main() {
let name = String::from("abc");
show_len(name);
println!("{}", name);
}
这里会出现报错:”^^^^ value borrowed here after move“
这里就好比是,把name的所有者交给了函数show_len的s,此时name的值在内存里就释放掉了。
就上面的解决办法来说,我们可以加一个引用
fn show_len(s: &String) { // s 就没有获取所有权
println!("{}", s.len());
}
fn main() {
let name = String::from("abc");
show_len(&name); // 传入的是对 name 的引用
println!("{}", name);
}// 函数结束 name 才废掉
修改原字符串
修改值,我们可以使用到上面说的push_str函数,但是这个是不可变的,所以我们需要加上mut
fn change(s: &mut String) {
s.push_str("_19");
}
fn main() {
let mut name = String::from("abc");
change(&mut name);
println!("{}", name);
}
// 打印内容 abc_19