Ambiguous associated type when making a type alias for a numeric type

Viewed 291

I'm writing a geometry library and am manipulating values that represent lengths. I've written a type alias for a type that represents lengths, currently set to f64 but could in the future be changed to f32 or possibly other numeric types (perhaps dependent on precision and space requirements):

type Length = f64;

All the functions and structs in this library would then be written in terms of this type, such as this function:

fn circumference(radius: Length) -> Length {
    Length::consts::PI * radius * radius
}

However, the function above causes the following compiler error:

   Compiling playground v0.0.1 (/playground)
error[E0223]: ambiguous associated type
 --> src/lib.rs:4:5
  |
4 |     Length::consts::PI * radius * radius
  |     ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<f64 as Trait>::consts`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0223`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

but doesn't give any elaboration about the Trait I should use — presumably I need to write <Length as Trait>::consts::PI for some appropriately chosen Trait, but it doesn't tell me what this trait should be.

Playground link

What trait should it be?

1 Answers

You can't access std::f64::consts::PI through the type alias Length. That PI is a module constant belonging to the consts submodule of std::f64. It isn't associated with the f64 primitive type.

To access the module constant, you'll need to either use its fully qualified name (::std::f64::consts::PI) or import one of the modules in its path and use a partially qualified name. For example,

use std::f64;
fn circumference(radius: Length) -> Length {
    f64::consts::PI * radius * radius
}

// or

use std::f64::consts as foo;
fn circumference(radius: Length) -> Length {
    foo::PI * radius * radius
}

To avoid intermixing Length with its current definition, you can always define a local constant like

const LENGTH_PI: Length = f64::consts::PI as Length;

This way, if the type of Length changes in the future, you only have to replace f64::consts::PI once.

Related