std1.97.1——result模块总览

0. Result模块简介

  使用Result类型进行错误处理。
  Result<T, E>是用于返回和传播错误的类型。它是一个枚举,包含变体Ok(T),表示成功并包含一个值;以及Err(E),表示错误并包含一个错误值。

enum Result<T, E> {
	Ok(T),
	Err(E),
}

  函数在预期出现可恢复错误时返回Result。在std crate中,Result最常用于I/O。
  一个返回Result的简单函数可以如下定义和使用:

#[derive(Debug)]
enum Version {
	Version1,
	Version2,
}

fn parse_version(header: &[u8]) -> Result<Version, &'static str> {
	match header.get(0) {
		None => Err("invalid header length"),
		Some(&1) => Ok(Version::Version1),
		Some(&2) => Ok(Version::Version2),
		Some(_) => Err("invalid version"),
	}
}

fn main() {
	let version = parse_version(&[1, 2, 3, 4]);
	match version {
		Ok(v) => println!("working with version: {v:?}"),
		Err(e) => println!("error parsing header: {e:?}"),
	}
}

在这里插入图片描述

1. Result必须被使用(Rust程序设计语言中提过了)

  使用返回值指示错误的一个常见问题是,很容易忽略返回值,从而导致错误未被处理。Result被标注了#[must_use]属性,当Result值被被忽略时,编译器会发出警告。这使得Result特别适合于那些可能遇到错误但不返回有用值的函数。
  考虑为I/O类型定义write_all方法,它属于Write trait:

use std::io;

trait Write {
	fn write_all(&mut self, bytes: &[u8]) -> Result<(), io::Error>;
}

  这个方法不产生值,但写入可能失败。处理错误情况至关重要,不要写成这样:

use std::fs::File;
use std::io::prelude::*;

fn main() {
	let mut file = File::create("valuable_data.txt").unwrap();
	// 如果write_all出错,我们将永远不知道,因为返回值被忽略了。
	file.write_all(b"important message");
}

  如果你在Rust中这样写,编译器会给你一个警告。
  如果你不想处理错误,可以用expect简单地断言成功。如果写入失败,它会panic,并提供一个大致有用的消息说明原因。

use std::fs::File;
use std::io::prelude::*;

fn main() {
	let mut file = File::create("valuable_data.txt").unwrap();
	file.write_all(b"important message").expect("failed to write message");
}

  用?将错误向上传播到调用栈:

fn write_message() -> io::Result<()> {
	let mut file = File::create("valuable_data.txt")?;
	file.write_all(b"important message")?;
	Ok(())
}

2. 问号运算符?

  当编写调用许多返回Result类型函数的代码时,错误处理可能很繁琐。问号运算符?隐藏了一些将错误向上传播到调用栈的样板代码。
  它将这段代码:

use std::fs::File;
use std::io::prelude::*;
use std::io;

struct Info {
	name: String,
	age: i32,
	rating: i32,
}

fn write_info(info: &Info) -> io::Result<()> {
	// 出错提前返回
	let mut file = match File::create("my_best_friends.txt") {
		Err(e) => return Err(e),
		Ok(f) => f,
	};
	if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) {
		return Err(e);
	}
	if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) {
		return Err(e);
	}
	if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) {
		return Err(e);
	}
	Ok(())
}

  替换为:

use std::fs::File;
use std::io::prelude::*;
use std::io;

struct Info {
	name: String,
	age: i32,
	rating: i32,
}

fn write_info(info: &Info) -> io::Result<()> {
	// 出错时提前返回
	let mut file = File::create("my_best_friends.txt")?;
	file.write_all(format!("name: {}\n", info.name).as_bytes())?;
	file.write_all(format!("age: {}\n", info.age).as_bytes())?;
	file.write_all(format!("rating: {}\n", info.rating).as_bytes())?;
	Ok(())
}

  在表达式末尾加上?,如果结果是Ok则获取其解包后的值;如果是Err,则提前从外层函数返回该Err。?可用于返回Result的函数,因为它提供了Err的提前返回功能。

3. 内存表示(暂时不知道这部分讲得什么玩意)

  Rust保证:当T或E中有一个类型满足Option的内存表示保证(称该类型为I),且另一个类型是大小为零且对齐为1的类型(即1-ZST)时,Result<T, E>与I(因此也与Option<I>)具有相同的大小、对齐和ABI。
  如果I是T,那么将类型为I的值t transmute为Result<T, E>(得到Ok(t)),以及将类型为Result<T, E>的值Ok(t) transmute为类型I(得到值t),没有运行时开销。如果I是E,同理,只是将Ok替换为Err。

参考

1、Rust std::result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值