std::error::FromError idiomatic usage
std::error::FromError idiomatic usage
我正在尝试在我的项目中尽可能广泛地涉及 std::error::FromError
特征,以利用 try!
宏。但是,不同 mods.
之间的这些错误转换让我有些迷茫
例如,我有 mod(或 crate)a
,它使用自己的 Error
类型进行一些错误处理,并为 io::Error
实现错误转换:
mod a {
use std::io;
use std::io::Write;
use std::error::FromError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<io::Error> for Error {
fn from_error(err: io::Error) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<(), Error> {
try!(writeln!(&mut io::stdout(), "Hello, world!"));
Ok(())
}
}
我也有mod b
同样的情况,但是实现了错误转换为num::ParseIntError
:
mod b {
use std::str::FromStr;
use std::error::FromError;
use std::num::ParseIntError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<ParseIntError> for Error {
fn from_error(err: ParseIntError) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<usize, Error> {
Ok(try!(FromStr::from_str("14")))
}
}
现在我在我当前的 mod super
,它有自己的 Error
类型,我的目标是编写这样的程序:
#[derive(Debug)]
struct Error(String);
fn func() -> Result<(), Error> {
println!("a::func() -> {:?}", try!(a::func()));
println!("b::func() -> {:?}", try!(b::func()));
Ok(())
}
所以我确实需要为我的 Error
类型实现 a::Error
和 b::Error
的转换:
impl FromError<a::Error> for Error {
fn from_error(a::Error(contents): a::Error) -> Error {
Error(contents)
}
}
impl FromError<b::Error> for Error {
fn from_error(b::Error(contents): b::Error) -> Error {
Error(contents)
}
}
好的,直到那个时候它都有效。现在我需要写这样的东西:
fn another_func() -> Result<(), Error> {
let _ = try!(<usize as std::str::FromStr>::from_str("14"));
Ok(())
}
这里出现了一个问题,因为没有从 num::ParseIntError
到 Error
的转换。所以看来我又得去实现了。但我为什么要这样做?已经实现了从 num::ParseIntError
到 b::Error
的转换,还有从 b::Error
到 Error
的转换。所以肯定有一种干净的方法可以让 Rust 在没有我明确帮助的情况下将一种类型转换为另一种类型。
所以,我删除了我的 impl FromError<b::Error>
块并尝试了这个毯子 impl:
impl<E> FromError<E> for Error where b::Error: FromError<E> {
fn from_error(err: E) -> Error {
let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
Error(contents)
}
}
它甚至奏效了!但是,我没有成功用 a::Error
重复这个技巧,因为 rustc 开始抱怨实现冲突:
experiment.rs:57:1: 62:2 error: conflicting implementations for trait `core::error::FromError` [E0119]
experiment.rs:57 impl<E> FromError<E> for Error where a::Error: FromError<E> {
experiment.rs:58 fn from_error(err: E) -> Error {
experiment.rs:59 let a::Error(contents) = <a::Error as FromError<E>>::from_error(err);
experiment.rs:60 Error(contents)
experiment.rs:61 }
experiment.rs:62 }
experiment.rs:64:1: 69:2 note: note conflicting implementation here
experiment.rs:64 impl<E> FromError<E> for Error where b::Error: FromError<E> {
experiment.rs:65 fn from_error(err: E) -> Error {
experiment.rs:66 let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
experiment.rs:67 Error(contents)
experiment.rs:68 }
experiment.rs:69 }
我什至能理解问题的根源(一种类型 FromError<E>
可以为 a::Error
和 b::Error
实现),但我不知道如何解决它。
从理论上讲,也许这是一种错误的方法,我的问题有另一种解决方案吗?或者我仍然必须在每个新的 module 中手动重复所有错误转换?
there is no conversion from num::ParseIntError
to Error
从概念上看,您确实做错了事。当库生成 io::Error
时,就像您的第一个示例一样,那么它应该 由该库 来决定如何处理该错误。但是,从你的问题来看,听起来你正在其他地方生成 io::Error
s ,然后想像第一个库那样对待它们。
这看起来很奇怪。我不希望将库 B 生成的错误交给库 A 并说 "wrap this error as if you made it"。也许您正在做的事情应该是适当库的一部分?然后它可以像往常一样处理错误。也许你可以只接受一个闭包并适当地调用错误转换。
So definitely there is a clean way for Rust to convert one type to another without my explicit help.
(强调我的)。这对我来说真的很可怕。隐式转换中应该允许多少步?如果有多个路径,或者即使有循环怎么办?将这些作为明确的步骤对我来说似乎是合理的。
I can even understand the origin of problem [...], but I can't get how to fix it.
我认为无法解决此问题。如果您可以用多种不同的方式为同一类型实现一个特征,那么根本无法在它们之间进行选择,因此代码会产生歧义并被编译器拒绝。
我正在尝试在我的项目中尽可能广泛地涉及 std::error::FromError
特征,以利用 try!
宏。但是,不同 mods.
例如,我有 mod(或 crate)a
,它使用自己的 Error
类型进行一些错误处理,并为 io::Error
实现错误转换:
mod a {
use std::io;
use std::io::Write;
use std::error::FromError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<io::Error> for Error {
fn from_error(err: io::Error) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<(), Error> {
try!(writeln!(&mut io::stdout(), "Hello, world!"));
Ok(())
}
}
我也有mod b
同样的情况,但是实现了错误转换为num::ParseIntError
:
mod b {
use std::str::FromStr;
use std::error::FromError;
use std::num::ParseIntError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<ParseIntError> for Error {
fn from_error(err: ParseIntError) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<usize, Error> {
Ok(try!(FromStr::from_str("14")))
}
}
现在我在我当前的 mod super
,它有自己的 Error
类型,我的目标是编写这样的程序:
#[derive(Debug)]
struct Error(String);
fn func() -> Result<(), Error> {
println!("a::func() -> {:?}", try!(a::func()));
println!("b::func() -> {:?}", try!(b::func()));
Ok(())
}
所以我确实需要为我的 Error
类型实现 a::Error
和 b::Error
的转换:
impl FromError<a::Error> for Error {
fn from_error(a::Error(contents): a::Error) -> Error {
Error(contents)
}
}
impl FromError<b::Error> for Error {
fn from_error(b::Error(contents): b::Error) -> Error {
Error(contents)
}
}
好的,直到那个时候它都有效。现在我需要写这样的东西:
fn another_func() -> Result<(), Error> {
let _ = try!(<usize as std::str::FromStr>::from_str("14"));
Ok(())
}
这里出现了一个问题,因为没有从 num::ParseIntError
到 Error
的转换。所以看来我又得去实现了。但我为什么要这样做?已经实现了从 num::ParseIntError
到 b::Error
的转换,还有从 b::Error
到 Error
的转换。所以肯定有一种干净的方法可以让 Rust 在没有我明确帮助的情况下将一种类型转换为另一种类型。
所以,我删除了我的 impl FromError<b::Error>
块并尝试了这个毯子 impl:
impl<E> FromError<E> for Error where b::Error: FromError<E> {
fn from_error(err: E) -> Error {
let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
Error(contents)
}
}
它甚至奏效了!但是,我没有成功用 a::Error
重复这个技巧,因为 rustc 开始抱怨实现冲突:
experiment.rs:57:1: 62:2 error: conflicting implementations for trait `core::error::FromError` [E0119]
experiment.rs:57 impl<E> FromError<E> for Error where a::Error: FromError<E> {
experiment.rs:58 fn from_error(err: E) -> Error {
experiment.rs:59 let a::Error(contents) = <a::Error as FromError<E>>::from_error(err);
experiment.rs:60 Error(contents)
experiment.rs:61 }
experiment.rs:62 }
experiment.rs:64:1: 69:2 note: note conflicting implementation here
experiment.rs:64 impl<E> FromError<E> for Error where b::Error: FromError<E> {
experiment.rs:65 fn from_error(err: E) -> Error {
experiment.rs:66 let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
experiment.rs:67 Error(contents)
experiment.rs:68 }
experiment.rs:69 }
我什至能理解问题的根源(一种类型 FromError<E>
可以为 a::Error
和 b::Error
实现),但我不知道如何解决它。
从理论上讲,也许这是一种错误的方法,我的问题有另一种解决方案吗?或者我仍然必须在每个新的 module 中手动重复所有错误转换?
there is no conversion from
num::ParseIntError
toError
从概念上看,您确实做错了事。当库生成 io::Error
时,就像您的第一个示例一样,那么它应该 由该库 来决定如何处理该错误。但是,从你的问题来看,听起来你正在其他地方生成 io::Error
s ,然后想像第一个库那样对待它们。
这看起来很奇怪。我不希望将库 B 生成的错误交给库 A 并说 "wrap this error as if you made it"。也许您正在做的事情应该是适当库的一部分?然后它可以像往常一样处理错误。也许你可以只接受一个闭包并适当地调用错误转换。
So definitely there is a clean way for Rust to convert one type to another without my explicit help.
(强调我的)。这对我来说真的很可怕。隐式转换中应该允许多少步?如果有多个路径,或者即使有循环怎么办?将这些作为明确的步骤对我来说似乎是合理的。
I can even understand the origin of problem [...], but I can't get how to fix it.
我认为无法解决此问题。如果您可以用多种不同的方式为同一类型实现一个特征,那么根本无法在它们之间进行选择,因此代码会产生歧义并被编译器拒绝。