检查特征是否已实现

Sto*_*one 5 traits rust

如何检查结构是否实现某些特征并计算布尔结果

例如:

struct Foo;
struct Bar;

trait Qux {}
impl Qux for Foo {}
const fn is_qux<T>() -> bool { ... }

assert!(is_qux::<Foo>());
assert_ne!(is_qux::<Bar>());
Run Code Online (Sandbox Code Playgroud)

Cha*_*man 7

我知道三种实现方法。没有一个是完美的。

最好的方法是使用专业化

#![feature(specialization)]

const fn is_qux<T: ?Sized>() -> bool {
    trait IsQuxTest {
        const IS_QUX: bool;
    }
    impl<T: ?Sized> IsQuxTest for T {
        default const IS_QUX: bool = false;
    }
    impl<T: ?Sized + Qux> IsQuxTest for T {
        const IS_QUX: bool = true;
    }
    
    <T as IsQuxTest>::IS_QUX
}
Run Code Online (Sandbox Code Playgroud)

游乐场

然而,该解决方案存在多个问题:

  • 它仅限于夜间,并且专业化没有明确的稳定之路。
  • 专业化不健全。健全性问题不适用于这种特定情况,但是小心一点是有好处的,而且......
  • 目前的专业化还不明确。这与它不健全的原因相同:当与生命周期一起使用时,编译器可能不会选择正确的impl. 例如:
fn foo<'a>(v: &'a String) {
    struct Foo<'a>(&'a String);
    impl Qux for Foo<'static> {}
    println!("{}", is_qux::<Foo<'a>>());
}

fn main() {
    let v = String::new();
    static S: String = String::new();
    print!("is_qux::<Foo<'static>>() = "); foo(&S);
    print!("is_qux::<Foo<'non_static>>() = "); foo(&v);
}
Run Code Online (Sandbox Code Playgroud)

游乐场

输出:

is_qux::<Foo<'static>>() = true
is_qux::<Foo<'non_static>>() = true // ???
Run Code Online (Sandbox Code Playgroud)

下一个解决方案是使用deref 专业化或基于在特征方法之前选择固有方法的事实进行专业化(如果可能的话),如 @Aiden4 所建议的。不幸的是,正如前面所说,这不适用于泛型。

最后一种方法是最有趣的:它利用标准库中现有的专业化。例如,数组实现了Clone,但如果元素类型实现了Copy它们会使用按位复制来克隆自身(因为这样更快)。然而,Clone并不要求做同样的事情Copy(尽管强烈建议这样做)——这一事实使得这种行为可以观察到,并允许我们使用以下巧妙的技巧(这个想法来自这里):

is_qux::<Foo<'static>>() = true
is_qux::<Foo<'non_static>>() = true // ???
Run Code Online (Sandbox Code Playgroud)

游乐场

它可以调整为 std 中的许多专业化,例如这个

该解决方案在幕后使用专业化,因此专业化的警告 #3 仍然适用。然而,它使用现有的专业化,因此可以在稳定状态下使用 - 而且,它因此也是完全健全的。然而,它还有另一个警告:我不确定 Rust 的稳定性保证是否适用于这种情况,因此它将来可能会崩溃。除此之外,这个解决方案还不是——尽管如果将来const相关功能得到统一,它可能会成为。const