How do I imply the type of the value when there are no type parameters or ascriptions?

前端 未结 1 1270
花落未央
花落未央 2020-11-30 15:50

I am trying to convert my struct into a HashMap, but I am unable to do so while being in the impl block. Due to a crate constraint, I can only use &se

相关标签:
1条回答
  • 2020-11-30 16:13

    How do I imply the type of the value when there is no type parameters or ascriptions?

    In the vast majority of cases, the Rust compiler can infer the generic types of a type or function based on how values of the generic type are used.

    In some cases, there isn't enough information to infer exactly one type for a generic type, but there is always a way to pass type parameters when they exist.

    The two ways of doing so are to use the turbofish or fully qualified syntax at the call site.

    Turbofish

    The turbofish is the symbols ::<Type1, Type2, ...> appended to a function or type. See how it looks like a fish?

    Function example

    mem::size_of is defined as:

    pub const fn size_of<T>() -> usize.
    

    You can call it as:

    std::mem::size_of::<i8>()
    //               ^^^^^^ turbofish
    

    Type example

    Vec::new is defined as:

    impl<T> Vec<T> {
        pub fn new() -> Vec<T>
    }
    

    You can call it as:

    Vec::<u8>::new()
    // ^^^^^^ turbofish
    

    Multiple types

    If your function has multiple types, you need to specify something for each type in the same order as the definition:

    fn example<A, B>() {}
    
    fn main() {
        example::<i32, bool>();
        //         ^A  ^B
    }
    

    Fully qualified syntax

    If you need to disambiguate a method call to a specific trait with a type parameter, you can use the fully qualified syntax.

    From::from is defined as:

    trait From<T> {
        fn from(T) -> Self;
    }
    

    You can call it as:

        <String as From<&str>>::from("a")
    //  ^^^^^^^^^^^^^^^^^^^^^^ fully qualified syntax
    

    Partially inferring types

    If there are multiple types that can be provided but some of them can be inferred, you can still use _ to allow the compiler to infer that specific type.


    Here, I use the turbofish on the Into type for your code:

    let json_object = *Into::<HashMap<String, Value>>::into(self);
    

    That's not your problem though.

    For this line to be valid:

    let json_object: HashMap<String, Value> = *self.into();
    

    The result of the call to self.into() must be something that could be dereferenced to produce the type HashMap<String, Value>. How is the compiler expected to know what that is? It's also not what you want.

    All you have is &self, so that's what you have to convert from. Implement the trait for a reference to your struct:

    impl<'a> From<&'a WeatherSettings> for HashMap<String, Value> {
        fn from(weather: &'a WeatherSettings) -> HashMap<String, Value> {
            let mut json_object = HashMap::new();
            json_object.insert("unit".to_owned(), Value::String(weather.unit.clone()));
            json_object.insert("forecast_days".to_owned(), Value::Int(weather.forecast_days));
            json_object.insert("data".to_owned(), Value::String(weather.data.clone()));
            json_object
        }
    }
    

    This means you cannot move the strings over, but instead have to copy them. That's the restriction placed by the &self.

    0 讨论(0)
提交回复
热议问题