#traits #proc-macro #attributes #auto #auto-trait #enforces

must-implement-trait

一个属性 proc-macro,强制类型(自动)实现指定的特质。

1 个不稳定版本

0.1.0 2020 年 8 月 3 日

#1979开发工具

MIT 许可证

9KB
91

must-implement-trait

CI Badge

一个属性 proc-macro,强制类型(自动)实现指定的特质。

用法

must_implement_trait 属性应用于您的结构体或枚举类型

use must_implement_trait::must_implement_trait;

#[must_implement_trait(Send)]
struct Resources {
    data: Rc<String>,
}

#[must_implement_trait(Send, UnwindSafe)]
enum ConfigSource {
    File(String),
    Database(DatabaseAdapter)
}

该属性可以接受一个或多个特质名称作为参数;它将强制实现所有这些特质。

动机

某些特质,尤其是 SendSync,是 自动特质。这意味着它们由编译器自动实现,很少手动实现(或未实现)。它们的实现是隐式的,并且对读者来说不明显,除非查看文档。

作为库作者,您可能希望向消费者保证您的公开接口将携带这些特质。在自己的代码中,这也有助于在未实现的地方产生错误,而不是在由于特质约束违反而无法编译的消费者附近产生错误。

考虑以下示例(examples/async-future-send.rs

struct Resources {
    data: Rc<String>,
}

struct MyResourceManager {}

#[async_trait]
impl ResourceManager for MyResourceManager {
    async fn update_resources(resources: &Resources) {
        // Some code to update resources...
    }
    
}

我们在 update_resources 函数中得到了一个错误,告诉我们

error: future cannot be sent between threads safely
  --> examples/async-future-send.rs:21:54
   |
21 |       async fn update_resources(resources: &Resources) {
   |  ______________________________________________________^
22 | |         // Some code to update resources...
23 | |     }
   | |_____^ future returned by `__update_resources` is not `Send`
   |
   = help: within `Resources`, the trait `std::marker::Sync` is not implemented for `std::rc::Rc<std::string::String>`

默认情况下,async-trait 要求返回的 Future 是 Send。这是一个相当自然的选择,因为 async 通常用于多线程上下文中。在这种情况下,因为我们使用了一个 Rc 而不是 Arc,所以 Resources 不是 Send;我们在使用站点得到了一个错误。如果 Resources 在其自己的存储库中,该存储库旨在用于异步上下文中,作者可能没有意识到他们通过引入 Rc 而引入了一个破坏性变更。

根据我的经验,如果在面向异步的代码库中工作,确保大多数或所有类型都是 Send + Sync 是有意义的;如果自动实现隐式更改,很容易破坏下游代码。

通过应用 must_implement_trait,错误被移动到类型声明

error[E0277]: `std::rc::Rc<std::string::String>` cannot be sent between threads safely
  --> examples/async-future-send.rs:11:1
   |
11 | #[must_implement_trait(Send)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
   |
   = help: within `Resources`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
   = note: required because it appears within the type `Resources`
   = help: see issue #48214
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

依赖项

~1.5MB
~35K SLoC