rust练习-生命周期、错误处理


类型转换

裸指针和代表内存地址的整数互相转换

// 填空
fn main() {
    let mut values: [i32; 2] = [1, 2];
    let p1: *mut i32 = values.as_mut_ptr();
    let first_address: usize = p1 as usize; 
    let second_address = first_address + 4; // 4 == std::mem::size_of::<i32>()
    let p2: *mut i32 = second_address as *mut i32; // p2 指向 values 数组中的第二个元素
    unsafe {
        // 将第二个元素加 1
        //
        *p2 += 1;
    }
    
    assert_eq!(values[1], 3);

    println!("Success!")
}

try_from/try_into

// TryFrom 和 TryInto 也被包含在 `std::prelude` 中, 因此以下引入是没必要的
// use std::convert::TryInto;

fn main() {
    let n: i16 = 256;

    // Into 特征拥有一个方法`into`,
    // 因此 TryInto 有一个方法是 ?
    let n: u8 = match n.try_into() {
        Ok(n) => n,
        Err(e) => {
            println!("there is an error when converting: {:?}, but we catch it", e.to_string());
            0
        }
    };

    assert_eq!(n, 0);

    println!("Success!")
}

String parse

// 为了使用 `from_str` 方法, 你需要引入该特征到当前作用域中
use std::str::FromStr;
fn main() {
    let parsed: i32 = "5 ".trim().parse().unwrap();
    let turbo_parsed = "10".parse::<i32>().unwrap();
    let from_str: i32 = "20".parse().unwrap();
    let sum = parsed + turbo_parsed + from_str;
    assert_eq!(sum, 35);

    println!("Success!")
}

Display trait

use std::fmt;

struct Point {
    x: i32,
    y: i32,
}

impl fmt::Display for Point {
    // 实现fmt时会自动实现to_string()
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "The point is ({}, {})", self.x, self.y)
    }
}

fn main() {
    let origin = Point { x: 0, y: 0 };
    // 填空
    assert_eq!(origin.to_string(), "The point is (0, 0)");
    assert_eq!(format!("{}", origin), "The point is (0, 0)");

    println!("Success!")
}

{}和{:?}

{}fmt

{}debug

{} 类似,{:?} 也是占位符:

  • {} 适用于实现了 std::fmt::Display 特征的类型,用来以更优雅、更友好的方式格式化文本,例如展示给用户
  • {:?} 适用于实现了 std::fmt::Debug 特征的类型,用于调试场景

其实两者的选择很简单,当你在写代码需要调试时,使用 {:?},剩下的场景,选择 {}

rust类型别名,带泛型

use std::num::ParseIntError;

// 填空
type Res<T> = std::result::Result<T, ParseIntError>;

// 使用上面的别名来引用原来的 `Result` 类型
fn multiply(first_number_str: &str, second_number_str: &str) -> Res<i32> {
    first_number_str.parse::<i32>().and_then(|first_number| {
        second_number_str.parse::<i32>().map(|second_number| first_number * second_number)
    })
}

// 同样, 这里也使用了类型别名来简化代码
fn print(result: Res<i32>) {
    match result {
        Ok(n)  => println!("n is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    print(multiply("10", "2"));
    print(multiply("t", "2"));

    println!("Success!")
}

map and_then

fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
    let a = n1_str.parse::<i32>()?;
    let b = n2_str.parse::<i32>()?;
    Ok(a*b)
    
    // n1_str.parse::<i32>().and_then(|n1| {
    //     n2_str.parse::<i32>().map(|n2| n1 * n2)
    // })
}

生命周期

image-20221202211247152

demo

struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&'a self) -> i32 {
        3
    }
}

fn main() {}

可以省略生命周期的几个例子


fn nput(x: &i32) {
    println!("`annotated_input`: {}", x);
}

fn pass(x: &i32) -> &i32 { x }

fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
    x
}

struct Owner(i32);

impl Owner {
    // Annotate lifetimes as in a standalone function.
    fn add_one(&mut self) { self.0 += 1; }
    fn print(&self) {
        println!("`print`: {}", self.0);
    }
}

struct Person<'a> {
    age: u8,
    name: &'a str,
}

enum Either<'a> {
    Num(i32),
    Ref(&'a i32),
}

fn main() {}