Rust入门笔记 3.切片、向量与字符串

yyi
yyi
2023-08-11 / 0 评论 / 131 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2023年08月11日,已超过275天没有更新,若内容或图片失效,请留言反馈。

Rust入门笔记——切片、向量与字符串

我在第一节中写了关于元组和数组的笔记,这章来扩充一些其他的复合类型

1 切片

还记得刚学 Go 的时候,我对切片和数组感到非常迷惑。

切片和数组类似,但它本质上是对数据值的部分引用。切片的长度在编译时未知。

切片是一个两个字的对象,第一个字是指向数据的指针,第二个是切片的长度,可用于借用数组的一部分。

// 修复代码中的错误,不要新增代码行!
fn main() {
    let arr = [1, 2, 3];
    let s1: [i32] = arr[0..2];

    let s2: str = "hello, world" as str;
}
// Sol : 
fn main() {
    let arr = [1, 2, 3];
    let s1: &[i32] = &arr[0..2];

    let s2: &str = "hello, world" as &str;
}

原来的[i32]str都是切片类型,复习一下:切片是对数据值的引用。因此,切片不拥有数据的所有权,所以在尝试把切片赋值给变量的时候,变量的类型必须是对切片的引用。

fn main() {
    let arr: [char; 3] = ['中', '国', '人'];

    let slice = &arr[..2];
    
    // 修改数字 `8` 让代码工作
    // 小提示: 切片和数组不一样,它是引用。如果是数组的话,那下面的 `assert!` 将会通过: '中'和'国'是char类型,char类型是Unicode编码,大小固定为4字节,两个字符为8字节。
    assert!(std::mem::size_of_val(&slice) == 16); // orig : 8
}

64 位系统下,一个字是 8bytes,所以一个切片是 16.

fn main() {
   let arr: [i32; 5] = [1, 2, 3, 4, 5];
  // 填空让代码工作起来
  // let slice: __ = __;
  let slice: &[i32] = &arr[1..4];
  assert_eq!(slice, &[2, 3, 4]);
}

2 字符串和字符串切片

字符串字面量的类型是&str,标准库中的 String也是 Rust 的字符串类型

str 就是字符串切片,我们前面声明字符串都是用String::from而不是直接写字符串,就是因为 let s = "hello" 中这个 s 会成为一个 &str 类型的变量。

String 使用 UTF-8 编码,底层存储是 Vec<u8> 本节后面会提到 Vec。

// 基础类型转换为字符串
let one = 1.to_string();
let slice = "slice".to_string();
let slice1 = String::from("this is &str")
// 字符串追加
let mut s1 = String::from("base");
s1.push_str("str");
s1.push('c');
// 用 + 拼接
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + "-" + &s2;
// 字符串长度
let len = s1.len();
// 字符串截取
let sub = &s1[..2];
// 字符串替换
let s = String::from("Hello, dogs");
let s1 = s.replace("dogs", "world");
// 修复所有错误,并且不要新增代码行
fn main() {
    let  s = String::from("hello");
    s.push(',');
    s.push(" world");
    s += "!".to_string();

    println!("{}", s)
}
// Sol
fn main() {
    let mut s = String::from("hello");
    s.push(',');
    s.push_str(" world");
    s += &"!".to_string();

    println!("{}", s)
}
// String只能和 &str进行拼接,并且会移动 String 的所有权。
fn main() {
    let s1 = String::from("hello,");
    let s2 = String::from("world!");
         // let s3 = s1 + s2;
    let s3 = s1.clone() + &s2; 
    assert_eq!(s3,"hello,world!");
    println!("{}",s1);
}
/* 填空并修复所有错误 */
fn main() {
      // 和其他语言一样,使用 \ 来转义
    let raw_str = "Escapes don't work here: \x3F \u{211D}";
    assert_eq!(raw_str, "Escapes don't work here: ? ℝ");

    // 使用成对的 #" 、"# 来标定字符串,这样字符串中间就可以有"了
    let quotes = r#"And then I said: "There is no escape!""#;
    println!("{}", quotes);

    // 如果希望在字符串中使用 # 号,可以如下使用:
    let  delimiter = r###"A string with "# in it. And even "##!"###;
    println!("{}", delimiter);

    // 填空
    let long_delimiter = r###"Hello, "##""###;
    assert_eq!(long_delimiter, "Hello, \"##\"")
}

str、&str 和 String 都是 UTF-8 字符串,可以用 u8 数组实现字节数组

使用切片而不是索引访问字符串中的某个字符

fn main() {
    let s1 = String::from("hi,中国");
    // let h = s1[0];
      let h = &s1[..1];
    assert_eq!(h, "h");

    // let h1 = &s1[3..5];
      let h1 = &s1[3..6];
    assert_eq!(h1, "中");
}

3 向量

向量是线性表,用Vec<T>表示,其中 T 是向量中存放的数据类型

使用 push 方法追加单个元素

使用 append 拼接。

let vec: Vec<i32> = Vec::new(); 
let mut vec1 = vec![1, 2, 4, 8]; 
let vec2 = vec![32, 64];
vec1.push(16); 
vec1.append(&mut vec2);
println!("{:?}", vec1);
// 1, 2, 4, 8, 16, 32, 64

使用 get 方法取出向量中的值

let v = vec![1, 2, 4, 8];
v.get(0); // 这是一个 Option,后面流程控制会讲到

当然也可以直接用索引

let tmp1 = v[2];
let tmp2 = v[4]; // panic : index out of bounds
0

评论 (0)

取消