rust中vec、string、hashmap、错误处理


Vector

创建和删除

fn main() {
    // 创建vector,因为刚开始创建的时候不知道元素类型
    let v: Vec<i32> = Vec::new();

    // 或者刚开始不指定,后续加元素的时候会自动指定
    let mut v2 = Vec::new();
    v2.push(1);

    // 使用初始值创建
    let v3 = vec![1,2,3];

    // 删除vector
    // 离开作用域时,会删除
}

读取vector元素

  • 索引
  • get方法
let v = vec![1,2,3,4,5];
let second = &v[1];
println!("{}",second); //2

match v.get(1) {
    Some(second) => println!("haha"), //haha
    None => println!("no such thing"),
}

越界问题

let v = vec![1,2,3,4,5];
let second = &v[1];
//let second = &v[100];
// panicked at 'index out of bounds: the len is 5 but the index is 100'
//println!("{}",second); //2

match v.get(100) {
    Some(second) => println!("haha"), 
    None => println!("no such thing"), //no such thing
}

遍历

let v = vec![1,2,3,4,5];
for i in &v {
    println!("{}",i);
}

遍历更改:

fn main() {
    let mut v = vec![1,2,3,4,5];

    for i in &mut v {
        *i += 50;
    }

    println!("{:#?}",v);
    // [
    //     51,
    //     52,
    //     53,
    //     54,
    //     55,
    // ]
}

enum存储不同的数据类型

enum SpreadssheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}

fn main() {
    let row = vec![
        SpreadssheetCell::Int(3),
        SpreadssheetCell::Text("blue".to_string()),
        SpreadssheetCell::Float(1.234),
    ];
}

String

创建

String::new()
String::from("")
"".to_string();

demo

fn main() {
    let mut s = String::from("foo");
    s.push_str("bar");

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

image-20221122131932030

format!

不会取得参数所有权。

fn main() {
    let s1 = String::from("foo");
    let s2 = String::from("bar");

    let s = format!("{}-andyou {},",s1,s2);
    println!("{}",s);
    println!("{}",s1);
    println!("{}",s2);

    // foo-andyou bar,
    // foo
    // bar
}

索引访问

String是对vec<u8>的包装。

fn main() {
    let s = String::from("❤️✨");
    println!("{}",s.len()); //9
}

遍历

fn main() {
    let s = String::from("❤️✨");
    println!("{}",s.len()); //9

    for b in s.bytes() {
        print!("{} ",b); // 226 157 164 239 184 143 226 156 168
    }
    println!("");

    for b in s.chars() {
        print!("{} ",b); // ❤ ️ ✨
    }
    println!("");
}

切割

fn main() {
    let s = String::from("❤️✨");
    println!("{}",s.len()); //9
    let cc = &s[0..6];
    println!("{}",cc);
}

必须严格按照字符边界切割,否则会panic

HashMap

image-20221122165836447

数据存储在heap上。

collect方法创建HashMap

在元素类型为tuple的vector上使用collect方法,可以创建一个HashMap。demo:

fn main() {
    let colors = vec![String::from("Red"),String::from("Blue")];
    let scores = vec![1,2];

    let map: HashMap<_,_> = 
        colors.iter().zip(scores.iter()).collect();
}

所有权

image-20221122170541317


fn main() {
    let colors = vec![String::from("Red"),String::from("Blue")];
    let scores = vec![1,2];

    let map: HashMap<_,_> = 
        colors.iter().zip(scores.iter()).collect();

    let name = String::from("Blue");
    let score = map.get(&name);
    // pub fn get<Q>(&self, k: &Q) -> Option<&V>

    match score {
        Some(s) => println!("{}",s),
        None => println!("color not exist"),
    }

    println!("{}",name);

    for (k,v) in map {
        println!("{} {}",k,v);
    }

    // 2
    // Blue
    // Blue 2
    // Red 1
}

更新

HashMap大小可变

or_insert不存在才插入,返回到这个值的可变引用。

fn main() {
    let mut scores = HashMap::new();
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Red"), 20);
    scores.insert(String::from("Blue"), 30);

    println!("{:?}",scores); //{"Blue": 30, "Red": 20}

    scores.entry(String::from("Black")).or_insert(100);
    scores.entry(String::from("Blue")).or_insert(999);
    println!("{:?}",scores); // {"Black": 100, "Blue": 30, "Red": 20}
}

统计单词个数

fn main() {
    let text = "I love you love me";

    let mut map = HashMap::new();

    for word in text.split_whitespace() {
        let count = map.entry(word).or_insert(0);
        // 返回的是map k对应v的可变引用
        *count += 1;
    }
    println!("{:#?}",map);

    // {
    //     "you": 1,
    //     "I": 1,
    //     "me": 1,
    //     "love": 2,
    // }
}

错误处理

Rust没有异常机制。

  • 可恢复错误:Result
  • 不可恢复错误:panic!

当panic!宏执行时:打印错误信息、展开清理调用栈、退出程序。

image-20221122172819338

panic!

panic可以手动调用,也可以错误了自动panic。

let v = vec![1,2,3];
v[99];

// thread 'main' panicked at 'index out of bounds:
// the len is 3 but the index is 99', src\main.rs:5:5

Result枚举与可恢复的错误

来处理可能失败但是可以恢复的场景。

pub enum Result<T, E> {
    /// Contains the success value
    #[lang = "Ok"]
    #[stable(feature = "rust1", since = "1.0.0")]
    Ok(#[stable(feature = "rust1", since = "1.0.0")] T),

    /// Contains the error value
    #[lang = "Err"]
    #[stable(feature = "rust1", since = "1.0.0")]
    Err(#[stable(feature = "rust1", since = "1.0.0")] E),
}

image-20221122173626236

打开一个文件,如果不存在,则创建文件:


use std::fs::File;
fn main() {
    let f = File::open("1.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            std::io::ErrorKind::NotFound => match File::create("1.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Error create"),
            },
            other_error => panic!("Error open file"),
        }
    };
}

使用了很多match,后面会有闭包closure简化。

例如改良版:

image-20221122174541263

unwrap

unwrap是match表达式的一个快捷方法。

let f = File::open("1.txt").unwrap();

Ok就返回里面的值,Err就panic。

expect

类似unwrap,但是可以指定错误信息。

let f = File::open("1.txt").expect("无法打开1.txt");

传播错误

demo:

fn read_name_from_file() -> Result<String,io::Error> {
    let f = File::open("hello.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

?运算符

传播错误的一种简化方式。

fn read_name_from_file() -> Result<String,io::Error> {
    let mut f = File::open("hello.txt")?;
    // ? 成功就得到file,不成功就return err
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

?所接收到的错误会默认调用其中的from函数转化为返回的函数类型。但是不一定都能转。

链式调用

let mut s = String::new();

let mut f = File::open("hello.txt")?;.read_to_string(&mut s)?;
Ok(s)