【发布时间】:2019-11-26 21:52:07
【问题描述】:
我正在为 serde_json::value::Value 引用实现 Rust 的 TryFrom 特征,以及一般将 Vec<Value> 转换为 Vec<T> 的函数,其中 T 实现 TryFrom<&Value>。因为我必须在我的函数中为Value 引用指定生命周期,所以我无法返回T::try_from 的结果(借用值被丢弃)。
我尝试了另一种可行的方法;创建我自己的特征,类似于TryFrom,但没有泛型。这可行,但我不明白为什么我不能使用 TryFrom 和泛型,因为特征已经存在。
我的通用代码引发编译时错误:
impl TryFrom<&Value> for Channel {
type Error = &'static str;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
let title = value.get("title").ok_or("couldn't find title property in json")?
.as_str().ok_or("title was not a string")?;
let name = value.get("user_name").ok_or("couldn't find user_name property in json")?
.as_str().ok_or("user_name was not a string")?;
Ok(Channel {
title: String::from(title),
user_name: String::from(name)
})
}
}
// I must add a lifetime below. Please ignore the self reference.
fn get_many_generic<'a, T: TryFrom<&'a Value>>(&self, url_str: &str) -> Result<Vec<T>, Box<dyn std::error::Error>> {
// perform_get returns a serde_json::Value
let mut value = &self.perform_get(url_str)?;
if let Value::Object(map) = value {
value = map.get("data").ok_or("found a map without a 'data' property when expecting an array")?;
}
if let Value::Array(vec) = value {
Ok(vec.iter()
.filter_map(|item|
match T::try_from(item) {
Ok(model) => Some(model),
Err(e) => {
println!("Could not deserialize value {}", item);
None
}
}
).collect())
}
else {
Err(Box::new(
Error::new(format!("Expected array from {}, but didn't receive one.", url_str))
))
}
}
我的代码有效:
pub trait TryFromValue where Self: std::marker::Sized {
fn try_from_value(value: &Value) -> Result<Self, Box<dyn Error>>;
}
impl TryFromValue for Channel {
fn try_from_value(value: &Value) -> Result<Channel, Box<dyn Error>> {
let title = value.get("title").ok_or("couldn't find title property in json")?
.as_str().ok_or("title was not a string")?;
let name = value.get("user_name").ok_or("couldn't find user_name property in json")?
.as_str().ok_or("user_name was not a string")?;
Ok(Channel {
title: String::from(title),
user_name: String::from(name)
})
}
}
fn get_many<T: TryFromValue>(&self, url_str: &str) -> Result<Vec<T>, Box<dyn std::error::Error>> {
// perform_get returns a serde_json::Value
let mut value = &self.perform_get(url_str)?;
if let Value::Object(map) = value {
value = map.get("data").ok_or("found a map without a 'data' property when expecting an array")?;
}
if let Value::Array(vec) = value {
Ok(vec.iter()
.filter_map(|item|
match T::try_from_value(item) {
Ok(model) => Some(model),
Err(e) => {
println!("Could not deserialize value {}. Error {}", item, e);
None
}
}
).collect())
}
else {
Err(Box::new(
Error::new(format!("Expected array from {}, but didn't receive one.", url_str))
))
}
}
为什么这种方法行得通,但第一个代码示例失败了?
【问题讨论】:
-
第一段代码的错误信息是什么?很难回答这个问题,因为当我编译它时,我收到一堆关于缺少导入和不正确的
&self参数的错误,但我不知道 你 看到了什么。请尝试创建一个minimal reproducible example,最好是the playground。 -
-
应用于你的问题,看起来像
fn get_many_generic<T: for<'a> TryFrom<&'a Value>>(...) -
@trentcl 你说得对,这解决了我的问题。我想是时候重新阅读 Rustnomicon 中的那一章了。谢谢!也很抱歉发布了一个骗局。
-
没有理由感到抱歉!重复的问题有时很有用;它们可以链接在一起,以帮助未来的提问者更轻松地找到答案。很高兴我能提供帮助!
标签: generics reference rust serde