【问题标题】:How can I implement a function differently depending on if a generic type implements a trait or not?如何根据泛型类型是否实现特征以不同方式实现函数?
【发布时间】:2018-07-02 17:38:20
【问题描述】:

我想根据泛型类型T 是否实现Debug 来使do_something 的实现成为条件。有没有办法做这样的事情?

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(&amp;Self),但我不确定。我的代码 sn-p 是我将首先尝试的。

【问题讨论】:

  • @Stargateur 我的意思是如果 T 实现 Trait 则执行 A ,如果 T 则执行 B >T 没有实现 Trait,所有这些都使用一个通用名称,例如 do_something(&amp;Self)
  • 不可能两者都必须在这种情况下实现特征。 :/ 也许你应该阅读 trait 以及如何使用它们。
  • 是的,我想是的,但只是想知道我是否不知道一些超高级的东西,但是在函数内部看到类似 if T impl Debug { A } else { B } 的东西会很酷,我认为这是可能的,因为它像条件编译,所有这些都可以在编译时检查。

标签: rust generic-programming


【解决方案1】:

这里是基于夜间功能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(&amp;self) 的特征。现在,我们为Foo&lt;T&gt; 定义了这个特征的两个impls:一个通用的“父”impl,它为所有T 实现,一个专门的“子”impl,它只为子集实现T 实现 Debug。子 impl 可以专门化来自父 impl 的项目。这些我们想要专门化的项目需要在父 impl 中使用 default 关键字进行标记。在您的示例中,我们希望专门化 do_something

【讨论】:

  • 我有这样的想法,但我不知道专业化功能。
猜你喜欢
  • 2021-07-02
  • 1970-01-01
  • 2019-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多