【发布时间】:2020-09-24 19:59:50
【问题描述】:
我一直在使用json crate(GitHub,crates.io),我决定实现一个辅助函数来解析 json 中的数字:
use std::convert::{TryInto, From, Infallible};
use json::number::Number;
use json::{self, JsonValue, JsonError};
use std::fmt;
use std::error::Error;
#[derive(Debug)]
enum ConvertError {
JsonError(JsonError),
InfallibleError(Infallible),
InvalidTypeError
}
impl fmt::Display for ConvertError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::JsonError(e) => e.fmt(f),
Self::InfallibleError(e) => e.fmt(f),
Self::InvalidTypeError => write!(f, "Field has an invalid type")
}
}
}
impl Error for ConvertError {}
impl From<JsonError> for ConvertError {
fn from(e: JsonError) -> Self {
Self::JsonError(e)
}
}
impl From<Infallible> for ConvertError {
fn from(e: Infallible) -> Self {
Self::InfallibleError(e)
}
}
fn test_num<T: From<Number>>(obj: JsonValue) -> Result<T, ConvertError> {
match obj {
JsonValue::Number(num) => Ok(num.try_into()?),
_ => Err(ConvertError::InvalidTypeError)
}
}
fn main() -> Result<(), Box<dyn Error>> {
let s = "{\"test_float\": 0.1, \"test_int1\": 1, \"test_int2\": 2}";
let mut parsed = json::parse(s)?;
// Works (From<f32> defined here: https://docs.rs/json/0.12.4/src/json/number.rs.html#344-361)
let num1: f32 = test_num(parsed["test_float"].take())?;
// Also works
let num2: i32 = match parsed["test_int1"].take() {
JsonValue::Number(num) => match num.try_into() {
Ok(n) => n,
_ => return Err(Box::new(ConvertError::InvalidTypeError))
},
_ => return Err(Box::new(ConvertError::InvalidTypeError))
};
// Doesn't work (From<i32> defined here: https://docs.rs/json/0.12.4/src/json/number.rs.html#495)
let num3: i32 = test_num(parsed["test_int2"].take())?;
println!("Number 1: {}", num1);
println!("Number 2: {}", num2);
println!("Number 3: {}", num3);
Ok(())
}
但是,当我尝试编译程序时,返回以下错误:
error[E0277]: the trait bound `i32: From<json::number::Number>` is not satisfied
--> src\main.rs:56:21
|
34 | fn test_num<T: From<Number>>(obj: JsonValue) -> Result<T, ConvertError> {
| ------------ required by this bound in `test_num`
...
56 | let num3: i32 = test_num(parsed["test_int2"].take())?;
| ^^^^^^^^ the trait `From<json::number::Number>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as From<NonZeroI32>>
<i32 as From<bool>>
<i32 as From<i16>>
<i32 as From<i8>>
and 2 others
特别有趣的是let num1: f32 = test_num(parsed["test_float"].take())?; 和内联函数确实没有有编译错误,而i32 变体有。
据我所知,From<f32> 和From<i32> 实现之间的唯一区别是i32 实现了via a macro。
这是我使用 trait 实现方式的错误、宏实现方式的错误还是编译器错误?
(我目前正在使用最新的夜间编译器:rustc 1.48.0-nightly (8b4085359 2020-09-23))
【问题讨论】:
-
宏实现了
From<i32> for Number和TryFrom<Number> for i32,但没有实现From<Number> for i32。 -
啊,你说得对,不知道我是怎么误读的,但它打开了一大堆蠕虫,因为
TryFrom<Number>::Error是NumberOutOfScope,它没有实现std::error::Error,所以我无法使用?进行隐式转换,就像我在 main 中所做的那样,一旦我弄清楚到那时是否没有其他人回答它,我会自己回答。