如何根据泛型类型是否实现特征来不同地实现函数?

时间:2018-07-02 17:38:21

标签: rust generic-programming

我想根据通用类型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 :(得分:3)

以下是基于夜间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
}

第一步是创建定义do_something(&self)的特征。现在,我们为impl定义了两个Foo<T>的特征:为所有impl实现的通用“父” T和专门的“子” {{1 }}仅针对其中impl实现T的子集实现。子级Debug可以专门处理父级impl的项目。我们要专门处理的这些项目需要在父impl中用default关键字标记。在您的示例中,我们要专门研究impl