簡體   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