将具有所有权的结构转换为使用生命期和借阅副本:不再默认?



我正在编写一个完全基于所有权的库。主要作为一个学术练习,我正在考虑将它迁移到使用寿命。给定这样的内容,

#[derive(Default)]
struct Foo { test: i32 }
#[derive(Default)]
struct Bar { foo: Foo }

现在我可以很容易地修改栏使用生命周期,

#[derive(Default)]
struct Foo { test: i32 }
struct Bar<'a> { foo: &'a Foo }

但是这会触发一个错误,

error[E0277]: the trait bound `&Foo: Default` is not satisfied
--> src/main.rs:6:18
|
5 | #[derive(Default)]
|          ------- in this derive macro expansion
6 | struct Bar<'a> { foo: &'a Foo }
|                  ^^^^^^^^^^^^ the trait `Default` is not implemented for `&Foo`
|
= help: the trait `Default` is implemented for `Foo`
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.

我怎样才能绕过这个?

带有借用类型的默认trait

Default trait只能在所有类型都被拥有的情况下自动派生。但这并不是说你不能创建自己的实现。但是"默认"引用必须存在于函数之外以满足借用检查器。这里我们创建了一个新的默认值它需要是常量然后我们创建了它的全局实例化

impl Foo {
const fn new_const_default() -> Self {
// must repeat Default.
Self { u32: 0 }
}
}
// // Note you can use `new_const_default` to implement Default
// // This eliminates having two potentially conflicting defaults
// impl Default for Foo {
//   fn default() -> Self { Self::new_const_default() }
// }
// Now we have a reference to a static global.
const GLOBAL_FOO: &'static Foo = &Bar::new_const_default();
impl<'a> Default for Bar<'a> {
fn default() -> Sequence<'a> {
Self {
foo: GLOBAL_FOO
}
}
}

用户提供另一个经常发现的将Foo的引用置于Bardefault范围之外的解决方法是要求用户将其发送进去。虽然这会改变你的API。

let foo = Foo::default();
let bar = Bar::new_with_foo( &foo );

尽管注意,这意味着Bar将不实现或满足Default