How can I implement a function differently depending on if a generic type implements a trait or not?

◇◆丶佛笑我妖孽 提交于 2019-12-11 12:18:02

问题


I'd like to make the implementation of do_something conditional based on if the generic type T implements Debug or not. Is there any way to do something like this?

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
}

I think one way to do this is to create a trait where we have to define do_something(&Self), but I'm not sure. My code snippet is what I will try first.


回答1:


Here is a solution based on the nightly feature specialization:

#![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
}

The first step is to create a trait which defines do_something(&self). Now, we define two impls of this trait for Foo<T>: a generic "parent" impl which is implemented for all T and a specialized "child" impl which is only implemented for the subset where T implements Debug. The child impl may specialize items from the parent impl. These items we want to specialize need to be marked with the default keyword in the parent impl. In your example, we want to specialize do_something.



来源:https://stackoverflow.com/questions/51141200/how-can-i-implement-a-function-differently-depending-on-if-a-generic-type-implem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!