Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Rust constant expressions use traits like Default?

This code gives an error:

#[derive(Default)]
struct A {
    b: Option<()>,
    c: Option<()>,
}

const a: A = A {
    b: None,
    ..Default::default()
};
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
 --> src/lib.rs:9:7
  |
9 |     ..Default::default()
  |       ^^^^^^^^^^^^^^^^^^

In this small example it's not a big problem, but if I have a struct composed by multiple structs that implement the Default trait, not being able to use it becomes at minimum an inconvenience.

While I could write this, it wouldn't have the flexibility that Default provides:

impl A {
    const fn new(b: Option<()>) -> Self {
        A { b, c: None }
    }
}

const a: A = A::new(None);

Is there any way to avoid doing that?

like image 533
praguevara Avatar asked Dec 14 '22 08:12

praguevara


2 Answers

The ..Default::default() syntax is not restricted to Default::default(), so you can write a const fn default-like function and use that inside of a constant:

struct A {
    b: Option<()>,
    c: Option<()>,
}

impl A {
    const fn new() -> A {
        A {
            b: None,
            c: None,
        }
    }
}

impl Default for A {
    fn default() -> A {
        // implementing using new() instead of #[derive]
        // to avoid diverging implementations
        A::new()
    }
}

const a: A = A {
    b: None,
    ..A::new()
};

Run in Playground

like image 148
Frxstrem Avatar answered Dec 19 '22 12:12

Frxstrem


No, it is not possible to use traits in a constant context. This is still being discussed in RFC #2632 — Calling methods on generic parameters of const fns.

See also:

  • Can I use const with overloading operators in Rust?
like image 35
Shepmaster Avatar answered Dec 19 '22 11:12

Shepmaster