Trait method resolution fails / How to write clear type conversions

I am curious why trait resolution fails in the below case. Is it that the From trait can only be invoked with a precise type, and &[u8;100] is not quite &[u8] ? That's my presumption.

This type of behavior can be confusing when there is a lot of Rust advice out there to let automatic conversion do the work, e.g. from Rust by Example:

// Arrays can be automatically borrowed as slices
println!("borrow the whole array as a slice");
analyze_slice(&xs);

Also the std::array docs don't really help out the confused user:

Arrays coerce to slices ( [T] ), so a slice method may be called on an array. Indeed, this provides most of the API for working with arrays. Slices have a dynamic size and do not coerce to arrays.

This is made more confusing to me because there's no explicit conversion method from a std::array to a std::slice (something like Vec's to_slice method). You have to do something "slicey enough", which just seems mysterious.

Any advice on how to explain this to a Rust newbie? Is there a clear way to write this code so a future reader could understand it best? Is &BYTES[..] really the best way to make a [u8;X] into a &[u8]? If so, could rustc help out by recommending that in this situation?

Here's a concrete example of what I'm talking about.

use bytes; // 0.5.4

fn look_at_slice(slice: &[u8]) {
    // empty
}

fn main() {
    let BYTES = [0u8;100];
    
    // automatic conversion to slice works here
    look_at_slice(&BYTES);
    
    // automatic conversion to slice fails.
    bytes::BytesMut::from(&BYTES);

    // "slicey enough" behavior fixes the method resolution
    bytes::BytesMut::from(&BYTES[..]);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `bytes::bytes_mut::BytesMut: std::convert::From<&[u8; 100]>` is not satisfied
  --> src/main.rs:14:5
   |
14 |     bytes::BytesMut::from(&BYTES);
   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<&[u8; 100]>` is not implemented for `bytes::bytes_mut::BytesMut`
   |
   = help: the following implementations were found:
             <bytes::bytes_mut::BytesMut as std::convert::From<&'a [u8]>>
             <bytes::bytes_mut::BytesMut as std::convert::From<&'a str>>
   = note: required by `std::convert::From::from`

error: aborting due to previous error

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

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

As for explaining why the from fails, it's because you're trying to do a conversion that requires three states, and the compiler won't guess what the middle state should be. Maybe there are several options? Even if not, what if a future change introduces more options?

1 Like

So am I right that &[u8;100] is not quite &[u8] and that's why the trait method resolution fails? I can't find that explicitly written anywhere.

If so, it seems to me that those statements that "arrays can be borrowed as slices" aren't quite correct, because the slice type that people care about is the unsized slice type. How often do you see a sized slice in a API?

I'm not saying the type system should be changed, nor am I saying that the meaning of borrowing a [T] should be changed, but maybe the docs should be changed? Or perhaps a rustc helper could happen?

You can also force the coercion with &array as &[_]

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.