简体   繁体   中英

Why does Rust assignment of const from trait to trait not work?

I'm trying to assign an associated const defined in one trait to another trait which doesn't work as expected. Here's a minimal example with 3 traits and one struct:

trait A {
    const X: i32 = 1;
}

struct S;

impl A for S {}

trait B {
    const Y: i32 = A::X;
}

trait C {
    const Y: i32 = S::X;
}

fn main() {}

The corresponding compiler error is:

error[E0283]: type annotations required: cannot resolve `_: A`
  --> src/main.rs:10:20
   |
10 |     const Y: i32 = A::X;
   |                    ^^^^
   |
note: required by `A::X`
  --> src/main.rs:2:5
   |
2  |     const X: i32 = 1;
   |     ^^^^^^^^^^^^^^^^^

The explanation for E0283 tells me what the code reveals: I can assign from a concrete type but not the trait itself. But where the E0283 example uses an undefined function I have an already defined value. Why is that so and how can this be bypassed?

The problem is that any struct that implements A could define its own value for X . Thus, simply stating A::X in the context of trait B does not offer enough information for the compiler as to which impl of A should be chosen.

If you want that something that impl ements B also impl ements A , you can try the following (I have no compiler at hand, but the idea should be clear):

trait B : A {
    const Y: i32 = <Self as A>::X;
}

Traits are supposed to be implemented by a concrete type, and are not supposed to define a constant on their own that can't be changed in implementors. What you specified is a default value, rather than a value all implementors must adhere to. You wouldn't need a trait if all types must have the same X value.

Therefore A::X is not a well defined value.

Here is an example showing why:

trait A {
    const X: i32 = 1;
}

struct S;

impl A for S {}

struct R;

impl A for R {
    const X: i32 = 42;
}

fn main() {
    println!("S: {}", S::X);
    println!("R: {}", R::X);
    println!("S: {}", <S as A>::X); // A::X alone is ambiguous
    println!("R: {}", <R as A>::X);
}

(link to playground)

What you are doing is similar to trying to call a default function on a trait, here the error E0283:

trait A {
    fn get_x() -> i32 {
        1
    }
}

struct S;

impl A for S {}

struct R;

impl A for R {
    fn get_x() -> i32 {
        42
    }
}

fn main() {
    // A::get_x() is ambiguous but there are not:
    println!("S: {}", S::get_x());
    println!("R: {}", R::get_x());
    println!("S: {}", <S as A>::get_x());
    println!("R: {}", <R as A>::get_x());
}

(link to playground)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM