How to cast `&T` to `&[T;1]` when `T` has a concrete size?

I think &T is completely equal to &[T;1] in memory when T has a concrete size, so there should be a way to cast &T to &[T;1] such as via as keyword, but I don't know how to do.

They are two completely unrelated types, so adding yet another as special-case would be entirely the wrong thing to do, especially now that as is being phased out.

The conversion is already possible via the array::from_ref() function, and it should absolutely remain nothing more than a plain old function call.

13 Likes

Thanks. I didn't read the document carefully. :sweat_smile:

Can you elaborate on that? I sometimes use as.

2 Likes

Since many uses of as are error-prone and have safer alternatives (eg. floating-point to integer conversions, lossy integer conversions, pointer casts), it's being considered that it should be largely replaced by those alternatives. It's fine to use as for now, this is not going to happen overnight.

2 Likes

Basically, we're slowly adding methods to types so that the name of the method says what kind of thing you're doing, rather than just seeing as and needing to run full type inference in your head to figure it out.

For example, *const T as *const U is (since 1.38) best done via https://doc.rust-lang.org/std/primitive.pointer.html#method.cast, to emphasize that you're keeping it a *const, just changing the pointee type. And starting in Rust 1.65, *const T as *mut T will be best done via https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.cast_mut, to emphasize that you're intentionally making it mut, but aren't changing the pointee type.

On the other hand, there's not yet good alternatives for truncating things like u64 as u16. (I'd never say people should use (x & 0xFFFF).try_into().unwrap(), even though it works, because it's so verbose.) So for those you should continue using as until lang+libs-api comes up with the right way to represent them outside of as.

6 Likes

I thought on as &[_] to coerce a reference to an array into a reference to a slice (Playground). I just noticed there is the as_slice method on it.

Hmmm… :thinking: so should I consider as &[_] as worse coding style than using .as_slice()? I find the first a bit more readable, but maybe that's just my preference.

I think the two ways are all sound because &[...] as &[_] doesn't make ambiguity. But if you like, as_slice may be a better alternative which makes your motive more clear.
On the other hand, maybe casting &[T; SIZE] to &[T] can be approximate as de-referencing. If the sized slice has corresponding methods, call it, or rustc will trying "de-reference" it to unsized slice to finish the function call.

Yes, but I sometimes stumbled upon some cases where auto-dereference didn't work and I needed to cast manually.

Personally, I like to use slice syntax &vec[..] or &array[..] for such a conversion. It's relatively short and represents the idea that you're borrowing it as an arbitrary range.

7 Likes

It is not dereference doesn't work but the thing dereference from also implements the same trait or has the methods with duplicated name, compare to the target it dereference to.
For example, call clone on Rc<u32> will result to a new Rc<u32> but not a u32. Because if it always doing dereference, then how to call clone on the origin? Compared with <Rc as Clone>::clone(&some), not always auto do dereference is the better design.
Btw, the above is for example, better using Rc::clone(&some) instead of some.clone().

It's possible that as &[_] will keep working, actually. One potential future is that as will keep working for anything that's an implicit coercion. (Aka let x: &[_] = &vec; works.) And there are very few input types for which as &[_] works at all, so it's not particularly confusing.

as is much more concerning for things like p as u64, where it's unclear whether it's supposed to be *p as u64 or p as usize as u64 or what.

1 Like

Yet I think rustc or rust-analyzer should recognize attempt to do that conversion using as operator (or even without any explicit conversion) and show special diagnostic pointing to from_ref's documentation.

1 Like