Is there a trait "As"?

I find that there is traits like From Into, but is there a trait like As? In there where T: As<f32> stats : the type which can be converted into f32 by using as?

Like this:

fn to_sum<T>(x: T) -> f32 
where 
    T: As<f32> // means the type that can be write as "i as f32"
{
    1f32 + x as f32
}

Nope, no such trait. num_traits::AsPrimitive is a decent stand in though.

4 Likes

This is before I came to Rust, but I think that AsRef trait is historically coming from the as conversion. Today these two things are distinct though.

1 Like

Yes, that'd be where T: Into<f32>, if you want infallible conversions, and where T: TryInto<f32, Error = YourError> for fallible conversions.

It doesn't use as though, which is actually fine since you should prefer .into() and .try_into() whenever possible instead. The reason for that is that as may truncate or otherwise yield surprising results under certain conditions, whereas the behavior of .into() and .try_into() can always be checked quickly by looking at their impl blocks.

4 Likes

No, it was generalizing ad-hoc conversion methods and proposed AsStr, AsPath style traits. AsRef, AsMut, From, Into, TryFrom, and TryInto are the trait-based infrastructure for conversions though; they sadly don't cover all casts. Probably can't without being magic; AFAIK as was never trait-based.

1 Like

I was thinking on AsRef being related to as somehow because of that As lifts over Deref comment related to #45742. Note it says "As" and not "AsRef". But like I said, I haven't been working with Rust back then.

Unfortunately there's no integer <-> float conversion in std without as, AFAICT.

I also struggle a bit when writing methods that shall be generic over f32 and f64. From a previous post of me:

I decided to implement my own trait in radiorust for my particular use case: radiorust::numbers::Float.

Because at least in the float -> int direction, in general there is no way to losslessly convert, and if truncating is the intended behavior, all the better to use code that makes that intention to truncate explicit.

In the int -> float direction there is the concern of overflow, and that is most likely why there is no impl From<u64> for f64 and the like, while there is e.g. an impl From for f64.

But that's the point, I don't see an "explicit" way to truncate? The closest I can find is the unsafe(!) to_int_unchecked - is possible UB if you screw up the checks better than as u32, which saturates? Depends on the context I suppose, but for me I'm going to stick with as for int <-> float conversion where "good enough" is perfect, which is every time so far for me.

A quick Google can fix that.

So in essence it'd become something like this:

 42.0_f32.trunc() as usize

At least until there is a stable way in stdlib to convert between them¹.
The value of the .trunc() here is that it communicates that it isn't a bug.

¹ There's FloatToInt but that is a nightly API ATM.

Considering I linked to another method on float primitives (in particular, the thing that FloatToInt is internal machinery for), I think you could assume that I saw that. It also doesn't make explicit the behavior of out of range values and NaN.

Making the truncation behavior explicit isn't terribly helpful when you need to read how as works anyway (and as far as I'm aware, every language with float to int conversion defaults to truncation, it's not a huge surprise)

So yeah, not convinced it's any better.

That's most likely because I'm not trying to convince you. I'm merely providing information, what others do with it (including completely disregarding it) is up to them.