Создание регистратора со значением, которое реализует определенные черты - PullRequest
0 голосов
/ 10 января 2020

Ниже приведен мой некомпилируемый код, чтобы увидеть мою ситуацию.

Я хочу создать регистратор с типом, который реализует Debug и Clone. Это потому, что я сначала хочу записать ошибку (думаю, мне нужно клонировать значение) на машине, а затем отправить ее в базу данных.

Я хочу инициализировать / использовать мой тип с помощью:

  • &str
  • String
  • Некоторый тип, который реализует Debug + Clone

Примечания:

  • Мне не нужны специализированные методы для каждого из вышеуказанных типов. У меня много методов, и я не хочу повторять дженерики.
  • Я не хочу вызывать мой тип с помощью дженерика c.
  • Мне все равно о каком-то дополнительном выделении, то есть, например, Box.
  • Я никогда не назначу результат экземпляра Logger переменной (может быть, это позволяет типу быть нестандартным?), я просто регистрирую несколько вещей.

Попытка Box вокруг требования Debug и Clone дает мне эту ошибку ...

только автоматические черты могут использоваться как дополнительные черты в объекте черты

... при использовании чего-то вроде этого:

pub fn new<D: Clone + Debug>(con: &'a DBCon, err: D) -> Logger

Код

struct DBCon;

struct Logger<'a> {
    con: &'a DBCon,
    err: ?? // Some type implementing Debug + Clone
}

impl<'a> Logger<'a> {
    pub fn new(con: &'a DBCon, err: ??) -> Logger {
        Logger { con, err }
    }

    pub fn log(self) {
        eprintln!("{:?}", self.err.clone())

        // Send self.err to database
    }

    // Additional log methods
}

fn main() {
    Logger::new(con: some_con, "err").log();

    Logger::new(con: some_con, "err".to_owned()).log();

    Logger::new(con: some_con, some_other_value_that_impl_Debug_and_Clone).log();
}

1 Ответ

1 голос
/ 10 января 2020

Вы можете сделать свой Logger generi c без указания параметров generi c на call сайтах:

use std::fmt::Debug;

struct DBCon;

struct Logger<'a, T: Debug + Clone> {
    con: &'a DBCon,
    err: T,
}

impl<'a, T: Debug + Clone> Logger<'a, T> {
    pub fn new (con: &'a DBCon, err: T) -> Self {
        Logger { con, err }
    }

    pub fn log (self) {
        eprintln!("{:?}", self.err.clone())
        // Send self.err to database
    }
    // Additional log methods
}

fn main() {
    let con = DBCon;

    Logger::new (&con, "err").log();
    Logger::new (&con, "err".to_owned()).log();
    // Logger::new (&con, some_other_value_that_impl_Debug_and_Clone).log();
}

Playground

На сайтах вызовов (в примере с функцией main) компилятор может автоматически угадывать типы, поэтому пользователям не нужно их печатать.

Также обратите внимание, что я использовал Self в качестве типа возврата для метода Logger::new. Это эквивалентно типу full , который я сейчас реализую, поэтому в данном случае Self является псевдонимом для Logger<'a, T>. С таким же успехом я мог бы написать: pub fn new (con: &'a DBCon, err: T) -> Logger<'a, T>, но не pub fn new (con: &'a DBCon, err: T) -> Logger, потому что Logger сам по себе является неполным типом, без параметров generi c, и компилятор не будет выводить типы в прототипах функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...