【发布时间】:2021-11-27 02:34:35
【问题描述】:
在下面的代码中:Rust Playground
//////////////////////////////////////
// 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 可以在该类型的实例上工作。
但是,当为用户定义的结构 Foo 实现 FooExternal 特征时,有一些样板代码(例如,为每个 tonic grpc 处理程序设置 opentelemetry 跟踪跨度上下文)很常见且容易出错且有点复杂要求最终用户输入。
所以我打算生成(想想:proc 宏,但 codegen 不是这里的问题!)FooExternal 的常见样板实现,并希望用户只关注核心应用程序逻辑,而不是担心复杂的以及一遍又一遍地键入相同的样板的无聊苦差事!
因此,我希望用户实现生成的特征FooImpl,而不是让用户为她的类型FooExternal 实现FooImpl,其中在FooExternal::foo 的生成的整体特征实现中,样板代码是发出,并将控制转发给FooImpl::foo_impl。
这是用户代码中的好东西:FooImpl 成为用户类型 Foo 的要求(使用 foo_external 时) - 如果用户忘记为 FooImpl 实现 Foo,编译器会拨打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
所以,我想知道是否曾经设计用于在这种情况下使用的特征毯实现(基本上将 FooImpl 和 FooExternal 绑定在一起,有点像扩展特征 trait FooExternal: FooImpl,但不完全是!),我可以依靠这种行为来定义我的代码生成逻辑来生成代码示例中的库代码吗?
任何见解将不胜感激!
【问题讨论】:
标签: rust