【Rust练习】25.Result

ops/2024/12/25 10:54:40/

题目来自:https://practice-zh.course.rs/result-panic/result.html

1

rust">
// 填空并修复错误
use std::num::ParseIntError;fn multiply(n1_str: &str, n2_str: &str) -> __ {let n1 = n1_str.parse::<i32>();let n2 = n2_str.parse::<i32>();Ok(n1.unwrap() * n2.unwrap())
}fn main() {let result = multiply("10", "2");assert_eq!(result, __);let result = multiply("t", "2");assert_eq!(result.__, 8);println!("Success!")
}

当你在IDE里敲下如上代码的时候,第一个问题就解决了:
IDE 中的错误显示
unwrap意味着遇到错误不再返回错误,而是当场panic,因此我们不能让它出现错误。

rust">use std::num::ParseIntError;fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {let n1 = n1_str.parse::<i32>();let n2 = n2_str.parse::<i32>();Ok(n1.unwrap() * n2.unwrap())
}fn main() {let result = multiply("10", "2");assert_eq!(result, Ok(20));let result = multiply("4", "2");assert_eq!(result.unwrap(), 8);println!("Success!")
}

2

rust">
use std::num::ParseIntError;// 使用 `?` 来实现 multiply
// 不要使用 unwrap !
fn multiply(n1_str: &str, n2_str: &str) -> __ {
}fn main() {assert_eq!(multiply("3", "4").unwrap(), 12);println!("Success!")
}

?unwrap 非常像,但是 ? 会返回一个错误,而不是直接 panic.

rust">fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {let n1 = n1_str.parse::<i32>()?;let n2 = n2_str.parse::<i32>()?;Ok(n1 * n2)
}fn main() {assert_eq!(multiply("3", "4"), Ok(12));println!("Success!")
}

问号在C++中大多用于三元表达式,Rust删除了这一功能。此外,Rust的这个问号设计显然借鉴了一些现代的语言(比如Kotilin用问号代表变量可能为空,让编译器放弃空指针检查)

3

rust">
use std::fs::File;
use std::io::{self, Read};fn read_file1() -> 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_file2() -> Result<String, io::Error> {let mut s = String::new();__;Ok(s)
}fn main() {assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string());println!("Success!")
}

其实就是将上面的写法转成问号表达式:

rust">fn read_file2() -> Result<String, io::Error> {let mut s = String::new();let f = File::open("hello.txt")?.read_to_string(&mut s)?;Ok(s)
}

另外这个unwrap_err,网上甚至都搜不到(Rust的普及还是任重道远),我看了下源代码的介绍,很有意思。

Returns the contained [Err] value, consuming the self value.
Panics if the value is an [Ok], with a custom panic message provided by the [Ok]'s value.

源代码如下:

rust">    #[inline]#[track_caller]#[stable(feature = "rust1", since = "1.0.0")]pub fn unwrap_err(self) -> EwhereT: fmt::Debug,{match self {Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t),Err(e) => e,}}

unwrap刚好相反,unwrap_err的调用者如果是Ok(msg),会panicmsg传入panic打印出来;如果是Err(msg),则返回msg
示例如下:

rust">let x: Result<u32, &str> = Ok(2);
x.unwrap_err(); // panics with `2`
rust">let x: Result<u32, &str> = Err("emergency failure");
assert_eq!(x.unwrap_err(), "emergency failure");

4

rust">use std::num::ParseIntError;// 使用两种方式填空: map, and then
fn add_two(n_str: &str) -> Result<i32, ParseIntError> {n_str.parse::<i32>().__
}fn main() {assert_eq!(add_two("4").unwrap(), 6);println!("Success!")
}

map

map的源代码如下:

rust">    #[inline]#[stable(feature = "rust1", since = "1.0.0")]pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E> {match self {Ok(t) => Ok(op(t)),Err(e) => Err(e),}}

用于在方法和返回Result之间执行某些操作。这些操作只会对正确的结果执行。
答案如下:

rust">fn add_two(n_str: &str) -> Result<i32, ParseIntError> {n_str.parse::<i32>().map(|num| num+2)
}

and_then

and_then的源代码如下:

rust">    #[inline]#[stable(feature = "rust1", since = "1.0.0")]#[rustc_confusables("flat_map", "flatmap")]pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {match self {Ok(t) => op(t),Err(e) => Err(e),}}

相比于mapand_then需要自行构造返回值,而map可以直接使用调用者的返回值。比如这里map直接返回num+2,相当于一种“替换”操作,返回的时候会自动加壳Ok;而and_then不再使用调用者的返回值了,需要自行构造Ok。这样会更加灵活,比如,也许你不需要Result,需要一个自定义的结构啥的。

rust">fn add_two(n_str: &str) -> Result<i32, ParseIntError> {n_str.parse::<i32>().and_then(|num| Ok(num + 2))
}

5

rust">use std::num::ParseIntError;// 使用 Result 重写后,我们使用模式匹配的方式来处理,而无需使用 `unwrap`
// 但是这种写法实在过于啰嗦..
fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {match n1_str.parse::<i32>() {Ok(n1)  => {match n2_str.parse::<i32>() {Ok(n2)  => {Ok(n1 * n2)},Err(e) => Err(e),}},Err(e) => Err(e),}
}// 重写上面的 `multiply` ,让它尽量简洁
// 提示:使用 `and_then` 和 `map`
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {// 实现...
}fn print(result: Result<i32, ParseIntError>) {match result {Ok(n)  => println!("n is {}", n),Err(e) => println!("Error: {}", e),}
}fn main() {let twenty = multiply1("10", "2");print(twenty);// 下面的调用会提供更有帮助的错误信息let tt = multiply("t", "2");print(tt);println!("Success!")
}

这个例子用and_then和map就很勉强了,降低了一点啰嗦,但是没完全去除:

rust">fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {n1_str.parse::<i32>().and_then(|n1| {n2_str.parse::<i32>().map(|n2|{n1*n2})})
}

最简单的办法还是之前提到的问号表达:

rust">fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {let n1: i32 = n1_str.parse()?;let n2: i32 = n2_str.parse()?;Ok(n1 * n2)
}

6

rust">use std::num::ParseIntError;// 填空
type __;// 使用上面的别名来引用原来的 `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!")
}

有点类似C的typedef和C++的using

rust">type Res<i32> = Result<i32, ParseIntError>;

http://www.ppmy.cn/ops/144833.html

相关文章

[cisco 模拟器] ftp服务器配置

首先确保 PC能ping通 FTP服务器 服务器端配置 打开FTP服务配置FTP用户名密码 客户端使用 > ftp {ftp服务器的IP} > 输入用户名密码 > put {文件路径}# dir不加盘符直接是从C盘开始定位; 可以使用dir看c盘下有什么文件 > get {文件名}例如 C:\>ftp 210.31.2…

fastadmin 框架 生成qr code 二维码图片,PHP 7.4版本

注意&#xff1a; 1、不同版本&#xff0c;安装qr code 用法不同。PHP8.0以上用qr code 4.0版本&#xff0c; PHP7.4用 qr code3.0版本 2、项目根目录安装&#xff1a; //安装3.0版本 composer require endroid/qr-code:^3.0//检查安装版本 composer show endroid/qr-code 选…

Postman常用测试脚本

状态码验证 // 验证状态码200 pm.test("Status code is 200", function () {pm.response.to.have.status(200); }); 响应时间验证 // 验证响应时间<500ms pm.test("Response time is within acceptable range", function () {pm.expect(pm.response.…

Docker、containerd、安全沙箱、社区Kata Containers运行对比

大家看了解决有意义、有帮助记得点赞加关注&#xff01;&#xff01;&#xff01; containerd、安全沙箱和Docker三种运行对比。 本文通过对比三种运行时的实现和使用限制、部署结构&#xff0c;帮助您根据需求场景了解并选择合适的容器运行。 一、容器运行时实现和使用限制…

3D几何建模引擎Parasolid功能解析

一、什么是Parasolid&#xff1f; Parasolid是由Siemens PLM Software开发的高精度精密几何建模引擎。它全面评估CAD&#xff08;计算机辅助设计&#xff09;、CAM&#xff08;计算机辅助制造&#xff09;、CAE&#xff08;计算机辅助工程&#xff09;、PLM&#xff08;产品生…

python怎么取消多行缩进

ipython缩进和取消缩进快捷键 整体缩进 &#xff08;1&#xff09;Ctrl】 &#xff08;2&#xff09;tab 取消缩进 &#xff08;1&#xff09;Ctrl【 &#xff08;2&#xff09;shift tab pycharm缩进和取消缩进快捷键 整体缩进 &#xff08;1&#xff09;tab 整体取…

gitlab克隆仓库报错fatal: unable to access ‘仓库地址xxxxxxxx‘

首次克隆仓库&#xff0c;失效了&#xff0c;上网查方法&#xff0c;都说是网络代理的问题&#xff0c;各种清理网络代理后都无效&#xff0c;去问同事&#xff1a; 先前都是直接复制的网页url当做远端url&#xff0c;或者点击按钮‘使用http克隆’ 这次对于我来说有效的远端u…

EMS(energy managment system)从0到1

EMS从0到1 写在前面准备目录&导航设计是什么&#xff1f;做什么&#xff1f;怎么做&#xff1f;我准备怎么做 写在结尾 写在前面 最近几年因为新能源产业的迅速升温&#xff0c;不仅导致我国能源结构的重新分配&#xff0c;也导致新能源相关产业蓬勃发展。我能接触到的就是…