Reputation: 407
Let we have the simple trait:
trait Object {
fn new() -> Self
where
Self: Sized;
}
and the struct implemented this trait:
struct Foo { /* internal fields */ }
impl Object for Foo {
fn new() -> Self {
Self { /* some magic */ }
}
}
Now we want to declare static variable in main.rs
, for example:
static FOO: Foo = Foo::new();
but we immediately get
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
So, if we want to construct static variables of Foo
type, we should declare a function like new
, but it should be different function, for example:
impl Foo {
const fn const_new() -> Self { Self { } }
}
static FOO: Foo = Foo::const_new();
But const
-twins of trait functions seems very odd. Is there an idiomatic way to write/implement such const
counterparts?
UPDATE
I expand answer of @KevinReid for clarity here. Given code works:
pub trait Object {
fn new() -> Self;
}
pub struct Foo {}
impl Foo {
pub const fn new() -> Self { // (1)
Self {}
}
}
impl Object for Foo {
fn new() -> Self { // (2)
println!("A-HA!");
Self::new() // no recursion, calls (1)
}
}
const FOO: Foo = Foo::new(); // calls (1)
fn main() {
let obj: Foo = Object::new(); // calls (2)
let foo = Foo::new(); // calls (1)
}
This code on Rust Playground.
Upvotes: 2
Views: 2532
Reputation: 3738
Based on the Rust compiler's recommendation, this is the idiomatic solution:
use once_cell::sync::Lazy;
static FOO: Lazy<Foo> = Lazy::new(Foo::new);
Upvotes: 1
Reputation: 43782
You can rename const_new
to just new
. When a trait method and an inherent method have the same name, the inherent method is always picked; it is not considered ambiguous.
This way, the same call can be written in both const and generic contexts, and there is no unusual name. (I would also suggest documenting the two functions to mention each other, so people don't assume that because one exists the other doesn't.)
That said, I can't say this idea is idiomatic; I haven't seen it done in a library I've used.
Upvotes: 3