Как я могу реализовать функцию по-разному в зависимости от того, реализует ли универсальный тип черту или нет? - PullRequest
0 голосов
/ 02 июля 2018

Я бы хотел сделать реализацию do_something условной в зависимости от того, реализует ли обобщенный тип T Debug или нет. Есть ли способ сделать что-то подобное?

struct A(i32);

#[derive(Debug)]
struct B(i32);

struct Foo<T> {
    data: T,
    /* more fields */
}

impl<T> Foo<T> {
    fn do_something(&self) {
        /* ... */
        println!("Success!");
    }

    fn do_something(&self)
    where
        T: Debug,
    {
        /* ... */
        println!("Success on {:?}", self.data);
    }
}

fn main() {
    let foo = Foo {
        data: A(3), /* ... */
    };
    foo.do_something(); // should call first implementation, because A
                        // doesn't implement Debug

    let foo = Foo {
        data: B(2), /* ... */
    };
    foo.do_something(); // should call second implementation, because B
                        // does implement Debug
}

Я думаю, что один из способов сделать это - создать черту, где мы должны определить do_something(&Self), но я не уверен. Сначала я попробую мой фрагмент кода.

1 Ответ

0 голосов
/ 02 июля 2018

Вот решение, основанное на ночной функции специализация :

#![feature(specialization)]

use std::fmt::Debug;

struct A(i32);

#[derive(Debug)]
struct B(i32);

struct Foo<T> {
    data: T,
    /* more fields */
}

trait Do {
    fn do_something(&self);
}

impl<T> Do for Foo<T> {
    default fn do_something(&self) {
        /* ... */
        println!("Success!");
    }
}

impl<T> Do for Foo<T>
where
    T: Debug,
{
    fn do_something(&self) {
        /* ... */
        println!("Success on {:?}", self.data);
    }
}

fn main() {
    let foo = Foo {
        data: A(3), /* ... */
    };
    foo.do_something(); // should call first implementation, because A
                        // doesn't implement Debug

    let foo = Foo {
        data: B(2), /* ... */
    };
    foo.do_something(); // should call second implementation, because B
                        // does implement Debug
}

Первый шаг - создать черту, которая определяет do_something(&self). Теперь мы определим два impl этой черты для Foo<T>: общий «родитель» impl, который реализован для всех T, и специализированный «потомок» impl, который реализован только для подмножества, где T реализует Debug. Дочерний impl может специализировать предметы от родителя impl. Эти элементы, которые мы хотим специализировать, должны быть помечены ключевым словом default в родительском элементе impl. В вашем примере мы хотим специализироваться do_something.

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