Michael Galuza
Michael Galuza

Reputation: 407

Rust: static, const, new and traits

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

Answers (2)

Kaplan
Kaplan

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);

Playground

Upvotes: 1

Kevin Reid
Kevin Reid

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

Related Questions