< 返回版块

Borber 发表于 2021-12-16 16:47

Tags:错误传递, "?"

大佬们, 如何比较优雅的使用 ? 同时传递函数里的 result 和 option 的错误, 对于返回结构我一直把握不了. 用enum吗? 大佬们能否给个样例.

评论区

写评论
苦瓜小仔 2021-12-16 18:13

BTW 你这 get_current_dir 函数逻辑的等价写法是:

use std::{env, io};

pub fn get_current_dir() -> Result<String, io::Error> {
    Ok(env::current_exe()?
        .parent()
        .map(|p| p.to_str())
        .flatten()
        .unwrap_or("/")
        .to_string())
}

fn main() {
    println!("当前运行目录: {:?}", get_current_dir());
}

--
👇
Borber: 目前的新版本:


use std::{env, io};

pub fn get_current_dir() -> Result<String , &'static str> {
    let current_exe = match env::current_exe() {
        Ok(path) => {path}
        Err(e) => {
            return Err("Cannot find the current running directory");
        }
    };
    match current_exe.parent() {
        None => {
            Ok(String::from("/"))
        }
        Some(path) => {
            Ok(path.to_str().unwrap().to_string())
        }
    }
}

#[test]
fn test() -> Result<(), io::Error>{
    println!(
        "当前运行目录: {:?}",
        get_current_dir().unwrap()
    );
    Ok(())
}

作者 Borber 2021-12-16 17:39

感谢大佬, 太爱你了! 🤝

--
👇
苦瓜小仔:

错误处理是 Rust 里面实践性很强的话题,你可以使用任何方式处理错误(包括 result 和 option,以及它们的混合体)。

既然你的意图是使用 ?,那么必须把返回值类型转成统一类型。最简的是 Result 转 Opton :

use std::env;

pub fn get_current_dir() -> Option<String> {
    Some(env::current_exe().ok()?.parent()?.to_str()?.to_string())
}

fn main() {
    println!("当前运行目录: {:?}", get_current_dir());
}

当然你可以统一成 Result 类型:

use std::{env, error};

pub fn get_current_dir() -> Result<String, Box<dyn error::Error>> {
    Ok(env::current_exe()?
        .parent()
        .ok_or("no parant")?
        .to_str()
        .ok_or("path is failed to convert to str")?
        .to_string())
}

fn main() {
    println!("当前运行目录: {:?}", get_current_dir());
}

任何方式都有优点和不足。

Option 的方式丧失了中途所有错误信息,比如这里你得到一个 None,你不知道它在哪个环节有问题。

Result 的方式保留了所有错误信息,甚至你可以定义自己的类型来组织各种错误。

这完全取决于你的取舍和判断。


不过我认为你对 Option 或 Result 的一些 Combinators 似乎不够熟悉,你可以去了解一下,再思考怎么设计错误 API 的问题。

https://doc.rust-lang.org/rust-by-example/error/option_unwrap/map.html

https://learning-rust.github.io/docs/e6.combinators.html

https://www.yuque.com/zhoujiping/programming/rust-grammar-details#HQG8x

苦瓜小仔 2021-12-16 17:26

错误处理是 Rust 里面实践性很强的话题,你可以使用任何方式处理错误(包括 result 和 option,以及它们的混合体)。

既然你的意图是使用 ?,那么必须把返回值类型转成统一类型。最简的是 Result 转 Opton :

use std::env;

pub fn get_current_dir() -> Option<String> {
    Some(env::current_exe().ok()?.parent()?.to_str()?.to_string())
}

fn main() {
    println!("当前运行目录: {:?}", get_current_dir());
}

当然你可以统一成 Result 类型:

use std::{env, error};

pub fn get_current_dir() -> Result<String, Box<dyn error::Error>> {
    Ok(env::current_exe()?
        .parent()
        .ok_or("no parant")?
        .to_str()
        .ok_or("path is failed to convert to str")?
        .to_string())
}

fn main() {
    println!("当前运行目录: {:?}", get_current_dir());
}

任何方式都有优点和不足。

Option 的方式丧失了中途所有错误信息,比如这里你得到一个 None,你不知道它在哪个环节有问题。

Result 的方式保留了所有错误信息,甚至你可以定义自己的类型来组织各种错误。

这完全取决于你的取舍和判断。


不过我认为你对 Option 或 Result 的一些 Combinators 似乎不够熟悉,你可以去了解一下,再思考怎么设计错误 API 的问题。

https://doc.rust-lang.org/rust-by-example/error/option_unwrap/map.html

https://learning-rust.github.io/docs/e6.combinators.html

https://www.yuque.com/zhoujiping/programming/rust-grammar-details#HQG8x

作者 Borber 2021-12-16 17:13

目前的新版本:


use std::{env, io};

pub fn get_current_dir() -> Result<String , &'static str> {
    let current_exe = match env::current_exe() {
        Ok(path) => {path}
        Err(e) => {
            return Err("Cannot find the current running directory");
        }
    };
    match current_exe.parent() {
        None => {
            Ok(String::from("/"))
        }
        Some(path) => {
            Ok(path.to_str().unwrap().to_string())
        }
    }
}

#[test]
fn test() -> Result<(), io::Error>{
    println!(
        "当前运行目录: {:?}",
        get_current_dir().unwrap()
    );
    Ok(())
}

作者 Borber 2021-12-16 16:54

或者 例如我现在写的这样一个小功能:

use std::{env, io};

pub fn get_current_dir() -> String { env::current_exe().unwrap().parent().unwrap().to_str().unwrap().to_string() }

#[test] fn test() -> Result<(), io::Error>{ println!( "当前运行目录: {:?}", get_current_dir() ); Ok(()) }

我该怎么消除一些unwrap 让他更优雅一点以及不那么影响用户交互(直接退出

1 共 5 条评论, 1 页