39、Unwarp(拆封)

Unwarpping

 

这个Unwarp,是Rust里面很重要的一个特性,中文可以翻译为拆封,不过我没见过有人用它的中文汉化的,还是保留英文名Unwarp

 

回到正题上来,上一节的习题为Ticket::new实现了可处理异常的Result返回值,Ticket::new现在返回一个Result,而不是直接对无效的输入数据panic。

这对函数调用者来说意味着什么呢?

 

错误(Failures)不能被隐式地忽略

 

与异常(exceptions)不同,Rust的Result强制我们在调用点处理错误。

如果我们调用一个返回Result的函数,Rust不允许我们隐式地忽略错误情况。

fn parse_int(s: &str) -> Result<i32, ParseIntError> {
    // ...
}

// This won't compile: we're not handling the error case.
// We must either use `match` or one of the combinators provided by 
// `Result` to "unwrap" the success value or handle the error.
let number = parse_int("42") + 2;

 

有了Result,然后呢?

 

调用返回Result的函数时,有两个关键选项:

  • 如果操作失败,则panic。这是使用unwarpexpect方法实现的。
// Panics if `parse_int` returns an `Err`.
let number = parse_int("42").unwrap();
// `expect` lets you specify a custom panic message.
// "expect" 为panic提供了自定义的错误信息
let number = parse_int("42").expect("Failed to parse integer");
  • 使用match表达式对Result进行解构,显式地处理异常情况。
match parse_int("42") {
    Ok(number) => println!("Parsed number: {}", number),
    Err(err) => eprintln!("Error: {}", err),
}

 

练习

 

题目:

// TODO: `easy_ticket` should panic when the title is invalid.
//   When the description is invalid, instead, it should use a default description:
//   "Description not provided".

pub fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
    /* TODO */
}

#[derive(Debug, PartialEq, Clone)]
pub struct Ticket {
    title: String,
    description: String,
    status: Status,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Status {
    ToDo,
    InProgress { assigned_to: String },
    Done,
}

impl Ticket {
    pub fn new(title: String, description: String, status: Status) -> Result<Ticket, String> {
        if title.is_empty() {
            return Err("Title cannot be empty".to_string());
        }
        if title.len() > 50 {
            return Err("Title cannot be longer than 50 bytes".to_string());
        }
        if description.is_empty() {
            return Err("Description cannot be empty".to_string());
        }
        if description.len() > 500 {
            return Err("Description cannot be longer than 500 bytes".to_string());
        }

        Ok(Ticket {
            title,
            description,
            status,
        })
    }

    pub fn title(&self) -> &str {
        &self.title
    }

    pub fn description(&self) -> &str {
        &self.description
    }

    pub fn status(&self) -> &Status {
        &self.status
    }
}

 

答案:

pub fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
    match Ticket::new(title.clone(), description, status.clone()) {
        Ok(ticket) => ticket,
        Err(error) => {
            if error.contains("Description") {
                Ticket::new(title, "Description not provided".to_string(), status).unwrap()
            } else {
                panic!("{error}");
            }
        }
    }
}

 

有两个难点,一个是.clone()什么时候写,另外一个是用error.contains("Description")追踪错误。

 

这一节的内容就先到这结束了。

阅读剩余
THE END