当没有类型参数或归属时,如何暗示值的类型?

ast*_*ver 2 rust

我正在尝试将我的 struct 转换为 a HashMap,但是在 impl 块中时我无法这样做。由于 crate约束,我只能&self用作resolve函数的参数。

use std::collections::HashMap;

pub enum Value {
    Int(i64),
    Object(HashMap<String, Value>),
}

pub struct WeatherSettings {
    forecast_days: i64,
}

impl WeatherSettings {
    fn resolve(&self) -> Value {
        let json_object: HashMap<String, Value> = *self.into();
        Value::Object(json_object)
    }
}

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

fn main() {}
Run Code Online (Sandbox Code Playgroud)

更直接,我得到错误:

use std::collections::HashMap;

pub enum Value {
    Int(i64),
    Object(HashMap<String, Value>),
}

pub struct WeatherSettings {
    forecast_days: i64,
}

impl WeatherSettings {
    fn resolve(&self) -> Value {
        let json_object: HashMap<String, Value> = *self.into();
        Value::Object(json_object)
    }
}

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

fn main() {}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 7

当没有类型参数或归属时,如何暗示值的类型?

在绝大多数情况下,Rust 编译器可以根据泛型类型的值的使用方式来推断类型或函数的泛型类型。

在某些情况下,没有足够的信息来推断泛型类型的确切类型,但总有一种方法可以在类型参数存在时传递它们。

这样做的两种方法是在调用站点使用turbofish完全限定的语法

涡轮鱼

turbofish 是::<Type1, Type2, ...>附加到函数或类型的符号。看看它看起来像一条鱼吗?

功能示例

mem::size_of 定义为:

pub const fn size_of<T>() -> usize.
Run Code Online (Sandbox Code Playgroud)

您可以将其称为:

std::mem::size_of::<i8>()
//               ^^^^^^ turbofish
Run Code Online (Sandbox Code Playgroud)

类型示例

Vec::new 定义为:

impl<T> Vec<T> {
    pub fn new() -> Vec<T>
}
Run Code Online (Sandbox Code Playgroud)

您可以将其称为:

Vec::<u8>::new()
// ^^^^^^ turbofish
Run Code Online (Sandbox Code Playgroud)

多种类型

如果您的函数有多种类型,则需要按照与定义相同的顺序为每种类型指定一些内容:

fn example<A, B>() {}

fn main() {
    example::<i32, bool>();
    //         ^A  ^B
}
Run Code Online (Sandbox Code Playgroud)

完全限定的语法

如果您需要使用类型参数消除对特定特征的方法调用的歧义,您可以使用完全限定的语法。

From::from 定义为:

trait From<T> {
    fn from(T) -> Self;
}
Run Code Online (Sandbox Code Playgroud)

您可以将其称为:

    <String as From<&str>>::from("a")
//  ^^^^^^^^^^^^^^^^^^^^^^ fully qualified syntax
Run Code Online (Sandbox Code Playgroud)

部分推断类型

如果可以提供多种类型,但其中一些可以推断,您仍然可以使用_允许编译器推断该特定类型。


在这里,我在Into您的代码类型上使用 turbofish :

let json_object = *Into::<HashMap<String, Value>>::into(self);
Run Code Online (Sandbox Code Playgroud)

不过那不是你的问题。

为了使这一行有效:

let json_object: HashMap<String, Value> = *self.into();
Run Code Online (Sandbox Code Playgroud)

调用的结果self.into()必须是可以取消引用以生成类型的东西HashMap<String, Value>。编译器如何知道那是什么?这也不是你想要的。

您所拥有的只是&self,所以这就是您必须从. 实现 trait 以引用您的结构:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着您不能移动字符串,而必须复制它们。这是&self.