首页 > 解决方案 > 为什么在 Rust 中使用泛型类型引用时必须指定生命周期?

问题描述

我正在实现 Rust 的TryFromtrait 作为serde_json::value::Value参考,以及一个将 a 转换Vec<Value>为 a的函数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))
        ))
    }
}

为什么这种方法有效,但第一个代码示例失败了?

标签: genericsreferencerustserde

解决方案


更高等级的特征界限(由 trentcl 建议)解决了这个问题。查看他们的评论。


推荐阅读