Как я подразумеваю тип значения, когда нет параметров типа или атрибутов?
Я пытаюсь преобразовать мою структуру в HashMap
, но я не могу это сделать, находясь в блоке impl. Из-за ограничения ящика я могу использовать только &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() {}
Проще говоря, я получаю ошибку:
error: the type of this value must be known in this context
--> src/main.rs:14:51
|
14 | let json_object: HashMap<String, Value> = *self.into();
| ^^^^^^^^^^^^
1 ответ
Как мне подразумевать тип значения, когда нет параметров типа или атрибутов?
В подавляющем большинстве случаев компилятор Rust может вывести универсальные типы типа или функции на основе того, как используются значения универсального типа.
В некоторых случаях недостаточно информации, чтобы вывести ровно один тип для универсального типа, но всегда есть способ передать параметры типа, когда они существуют.
Два способа сделать это - использовать turbofish или полностью определенный синтаксис на сайте вызова.
Turbofish
TurboFish это символы ::<Type1, Type2, ...>
добавляется к функции или типу. Видишь как выглядит рыба?
Пример функции
mem::size_of
определяется как:
pub const fn size_of<T>() -> usize.
Вы можете назвать это как:
std::mem::size_of::<i8>()
// ^^^^^^ turbofish
Пример типа
Vec::new
определяется как:
impl<T> Vec<T> {
pub fn new() -> Vec<T>
}
Вы можете назвать это как:
Vec::<u8>::new()
// ^^^^^^ turbofish
Несколько типов
Если ваша функция имеет несколько типов, вам нужно указать что-то для каждого типа в том же порядке, что и определение:
fn example<A, B>() {}
fn main() {
example::<i32, bool>();
// ^A ^B
}
Полностью определенный синтаксис
Если вам необходимо устранить неоднозначность вызова метода для определенной характеристики с параметром типа, вы можете использовать полный синтаксис.
From::from
определяется как:
trait From<T> {
fn from(T) -> Self;
}
Вы можете назвать это как:
<String as From<&str>>::from("a")
// ^^^^^^^^^^^^^^^^^^^^^^ fully qualified syntax
Частично выведенные типы
Если есть несколько типов, которые могут быть предоставлены, но некоторые из них могут быть выведены, вы все равно можете использовать _
чтобы позволить компилятору выводить этот конкретный тип.
Здесь я использую турбовину на Into
введите код:
let json_object = *Into::<HashMap<String, Value>>::into(self);
Это не твоя проблема, хотя.
Чтобы эта строка была действительной:
let json_object: HashMap<String, Value> = *self.into();
Результат звонка self.into()
должно быть что-то, что может быть разыменовано для получения типа HashMap<String, Value>
, Как компилятор должен знать, что это такое? Это также не то, что вы хотите.
Все что у вас есть &self
, так что это то, что вы должны конвертировать из. Реализуйте черту для ссылки на вашу структуру:
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
}
}
Это означает, что вы не можете переместить строки, а должны скопировать их. Это ограничение, наложенное &self
,