«метод не может быть вызван для объекта признака» в реализации отдельного признака - PullRequest
1 голос
/ 04 июня 2019

Я сталкиваюсь с ошибкой «метод не может быть вызван для объекта признака» с отдельной реализацией признака.

Это мой минимальный воспроизводимый пример:

Cargo.toml

[package]
name = "mrp"
version = "0.1.0"
authors = ["Empty2k12"]
edition = "2018"

[dependencies]
futures = "0.1.27"
tokio = "0.1.20"
serde = { version = "1.0.92", features = ["derive"] }
serde_json = { version = "1.0" }

main.rs

use serde::{Deserialize, Serialize};

pub mod integrations {
    pub mod serde_integration;
}

struct MyDbClient {}

#[derive(Serialize, Deserialize, Debug)]
pub struct Weather {
    temperature: i32,
}

#[cfg(test)]
mod tests {
    use super::Weather;
    use super::MyDbClient;
    use crate::integrations::serde_integration::MyDbSerdeORM;

    #[test]
    fn mrp() {
        let weather = Weather { temperature: 82 };

        MyDbClient {}.json_query::<Weather, ToString>(serde_json::to_string(&weather).unwrap())
    }
}

интеграций / serde_integration.rs

use serde::de::DeserializeOwned;

use super::super::MyDbClient;

use futures::Future;

pub trait MyDbSerdeORM {
    fn json_query<T: 'static, Q>(self, q: Q) -> Box<dyn Future<Item = Option<T>, Error = ()>>
    where
        Q: ToString,
        T: DeserializeOwned;
}

impl MyDbSerdeORM for MyDbClient {
    fn json_query<T: 'static, Q>(self, q: Q) -> Box<dyn Future<Item = Option<T>, Error = ()>>
    where
        Q: ToString,
        T: DeserializeOwned,
    {
        Box::new(futures::future::ok(Some(
            serde_json::from_str(&q.to_string()).unwrap(),
        )))
    }
}
error: the `json_query` method cannot be invoked on a trait object
  --> src/main.rs:27:23
   |
27 |         MyDbClient {}.json_query::<Weather, ToString>(serde_json::to_string(&weather).unwrap())
   |                       ^^^^^^^^^^
   |
   = note: another candidate was found in the following trait, perhaps add a `use` for it:
           `use crate::integrations::serde_integration::MyDbSerdeORM;`

Ошибка также бесполезна, так как предлагает добавить уже существующий импорт.

Как исправить ошибку, присутствующую в моем MRE?Как это может быть реализовано лучше, более простовато?

1 Ответ

2 голосов
/ 04 июня 2019

Там - это простое решение вашей проблемы: поскольку вы определили структуру MyDbClient в своем собственном ящике, вы можете просто реализовать нужные методы для нее без указания другой черты. Это будет работать с вашим оригинальным примером:

use futures::Future;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

pub struct MyDbClient {
    pub url: String,
}

#[cfg(feature = "serde-orm")]
impl MyDbClient {
    pub fn json_query<T: 'static, Q>(self, q: Q) -> Box<dyn Future<Item = Option<T>, Error = ()>>
    where
        Q: ToString,
        T: DeserializeOwned,
    {
        Box::new(futures::future::ok(Some(
            serde_json::from_str(&q.to_string()).unwrap(),
        )))
    }
}

#[cfg_attr(feature = "serde-orm", derive(Serialize, Deserialize, Debug))]
pub struct Weather {
    temperature: i32,
}

#[cfg(test)]
#[cfg(feature = "serde-orm")]
mod tests {
    use super::*;

    #[test]
    fn mrp() {
        let weather = Weather { temperature: 82 };

        let client: MyDbClient = MyDbClient {
            url: "localhost".to_owned(),
        };

        client.json_query::<Weather, _>(serde_json::to_string(&weather).unwrap());
    }
}

Это имеет один недостаток, поскольку вы не можете повторно использовать реализацию для типа, отличного от MyDbClient. Хотя это не сработает для всех, это, вероятно, подойдет для вашего варианта использования.

...