繁体   English   中英

使用特征毯实现来限制 Rust 中的类型特征边界?

[英]Use trait blanket implementation to restrict type trait bounds in Rust?

在下面的代码中: Rust 游乐场

  //////////////////////////////////////
 // External code from another crate //
//////////////////////////////////////

trait FooExternal {
    fn foo(&self);
}

fn foo_external(f: impl FooExternal) {
    f.foo();
}

  /////////////////////////////////////
 // My generated library code below //
/////////////////////////////////////

trait FooImpl {
    fn foo_impl(&self);
}

impl<T: FooImpl> FooExternal for T {
    fn foo(&self) {
        println!("foo: boilerplate");
        self.foo_impl();
    }
}

  ////////////////////////
 // My user code below //
////////////////////////

#[derive(Debug, Default)]
struct Foo;

// NB: the compiler will yell if FooImpl is not implemented
// try commenting out the impl below
impl FooImpl for Foo {
    fn foo_impl(&self) {
        println!("foo_impl");
    }
}

fn main() {
    println!("Hello, world!");
    let f = Foo::default();
    foo_external(f);
}

外部代码期望用户提供实现FooExternal的类型,因此foo_external可以在该类型的实例上工作。

但是,在为用户定义的 struct Foo实现FooExternal特征时,有一些样板代码(例如,为每个 tonic grpc 处理程序设置 opentelemetry 跟踪跨度上下文)很常见且容易出错,并且需要最终用户键入有点复杂出去。

所以我计划生成(想想:proc 宏,但 codegen 不是这里的问题!) FooExternal的常见样板实现,并希望用户只关注核心应用程序逻辑,而不用担心打字的复杂和无聊的琐事同样的样板一遍又一遍!

因此,与其让用户为她的类型Foo实现FooExternal ,我希望用户实现一个生成的特征FooImpl ,其中在FooExternal::foo的生成的整体特征实现中,发出样板代码,并将控制转发给FooImpl::foo_impl

这是用户代码中的好处: FooImpl成为用户类型Foo的要求(使用foo_external时) - 如果用户忘记为Foo实现FooImpl ,编译器会在调用foo_external(f)时对你大喊大叫!

因此,似乎特征毯实现有效地在FooExternal上绑定了FooImpl - 甚至编译器错误消息(当impl FooImpl for Foo被注释掉时)说:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Foo: FooImpl` is not satisfied
  --> src/main.rs:49:18
   |
49 |     foo_external(f);
   |                  ^ the trait `FooImpl` is not implemented for `Foo`
   |
note: required because of the requirements on the impl of `FooExternal` for `Foo`
  --> src/main.rs:23:18
   |
23 | impl<T: FooImpl> FooExternal for T {
   |                  ^^^^^^^^^^^     ^
note: required by a bound in `foo_external`
  --> src/main.rs:11:25
   |
11 | fn foo_external(f: impl FooExternal) {
   |                         ^^^^^^^^^^^ required by this bound in `foo_external`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error

所以,我想知道是否曾经设计用于这种情况的特征毯实现(基本上将FooImplFooExternal联系在一起,有点像扩展特征trait FooExternal: FooImpl ,但不完全是)? 我可以依靠这种行为来定义我的代码生成逻辑来生成代码示例中的库代码吗?

任何见解将不胜感激!

根据trait coherence rulesimpl<T: FooImpl> FooExternal for T必须与FooExternal在同一个 crate 中。 因此,如果您不控制定义FooExternal的板条箱,则无法执行此操作。

这些规则的设计是为了添加更多的 crate 永远不会在已经不存在的 trait 实现之间产生冲突。 只能有一个一揽子实现impl<T...> FooExternal for T (因为如果有多个,它们可能都适用于同一类型T ),并且只有定义FooExternal的板条箱才允许编写该实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM