Почему использование f32 :: consts :: E дает ошибку E0223, а std :: f32 :: consts :: E - нет?

Если я напишу:

let x = f32::consts::E;

Я получаю сообщение об ошибке:

error[E0223]: ambiguous associated type
  --> src/main.rs:32:21
   |
32 |             let x = f32::consts::E;
   |                     ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<f32 as Trait>::consts`

Но если я вместо этого напишу:

let x = std::f32::consts::E;

То все в порядке. Сообщение об ошибке сбивает с толку, потому что, насколько я понимаю, f32 - это конкретный конкретный тип, а не признак. Я не уверен, зачем мне использовать какой-то особый синтаксис признаков.

Что, по мнению компилятора, я делаю, и почему мое исправление помогает?


person Joseph Garvin    schedule 30.01.2019    source источник


Ответы (1)


Что компилятор думает, что я делаю

Есть модуль с именем f32 и есть тип с именем f32. Тип везде доступен по умолчанию, модуль - нет.

Без дополнительного импорта f32::foo лучше всего воспринимается компилятором как связанный тип для типа f32, но такого типа нет. Предполагается, что связанный тип происходит от признака, и предлагает вам более четко указать, что это за признак.

Когда вы выполняете std::f32, путь переносит модуль в область видимости, и затем можно найти вложенный модуль consts. Вы также можете:

use std::f32;
let x = f32::consts::E;

Это может произойти для любого типа, но обычно типы и модули используют разные стили именования (UpperCamelCase против snake_case):

struct my_type;

mod other {
    pub mod my_type {
        pub mod consts {
            pub const ZERO: i32 = 0;
        }
    }
}

fn example() {
    my_type::consts::ZERO;
}
error[E0223]: ambiguous associated type
  --> src/lib.rs:12:5
   |
12 |     my_type::consts::ZERO;
   |     ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<my_type as Trait>::consts`

Просто так случилось, что в примитивах используются все строчные буквы.

Вот код (сомнительной полезности), который показывает, как на самом деле может возникнуть связанный тип:

struct Consts;

impl Consts {
    const E: char = 'e';
}

trait Example {
    type consts;
}

impl Example for f32 {
    type consts = Consts;
}

fn example() {
    <f32 as Example>::consts::E;
}
person Shepmaster    schedule 30.01.2019
comment
Интересно, что он принимает ассоциированный тип из признака. если бы импортированный имплант заставлял f32 реализовывать трейт, с которым ассоциировался тип foo, был бы f32::foo действительным или вам всегда нужно явно указывать на это? - person Joseph Garvin; 31.01.2019
comment
@JosephGarvin Я не сразу понимаю, как заставить его использовать неявный синтаксис, нет. - person Shepmaster; 31.01.2019
comment
@JosephGarvin Связанные типы не разрешаются, но выполняются вызовы функций. Я не уверен, почему такая разница. Детская площадка - person trentcl; 31.01.2019