I have a library that I'm writing that's entirely based around ownership. Mostly as an academic exercise, I'm looking at migrating it to use lifetimes. Given something like this,
#[derive(Default)]
struct Foo { test: i32 }
#[derive(Default)]
struct Bar { foo: Foo }
Now I can easily modify bar to use lifetimes,
#[derive(Default)]
struct Foo { test: i32 }
struct Bar<'a> { foo: &'a Foo }
But that'll trigger an error,
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`.
How can I get around this?
The Default trait can only be automatically derived if all the types are owned. That's not to say you can't create your own implementation though. But the "default" reference must exist outside of the function to satisfy the borrow checker. Here we create a new default which needs to be constant and then we create a global instantiation of it,
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
}
}
}
Another often-found workaround which will place the reference to Foo
outside of the scope of Bar
's default
is to require the user to send it in. Though this will change your API.
let foo = Foo::default();
let bar = Bar::new_with_foo( &foo );
Though note, this means Bar
will not implement or satisfy Default
.