Motivation
When implementing cryptographic software in rust, you often deal with arrays. Eventually, you stumble upon rust’s strict type system. This serves as a tiny, trivial array types cheatsheet.
Starting with an example
Consider the following source code:
fn main() {
let a = [1, 2, 3];
}
-
a
is of type[{integer}; 3]
(thus an array with 3 elements) -
a[..]
is of type[{integer}]
(thus a slice which is a view into contiguous memory consisting of a pointer and a length internally) -
&a
or&a[..]
simply takes a reference to the respective types
Debugging the type
How can you debug the type?
-
Either trigger a compiler error. Use an assignment like
let x: bool = a[..];
or call an non-existing methoda.non_existent_method()
. -
By the way,
&a[..].non_existent_method()
calls&(a[..].non_existent_method())
. Hence(&a[..]).non_existent_method()
is required to call the method on its respective slice reference.
Another (limited) way is to use type_name which does not require nightly:
use std::any::type_name;
fn type_as_string<T>(_: &T) -> String {
String::from(std::any::type_name::<T>())
}
fn main() {
let a = [1, 2, 3];
println!("{}", type_as_string(&a));
// print "[i32; 3]"
}
The limitation comes from not being able to call type_as_string(&a[..])
. The compiler will complain that error[E0277]: the size for values of type
. This is the major limitation of slice which makes them unusable for function parameters and return values. With respect to debugging slices, you are stuck with the two approaches above. Be aware that [{integer}]
cannot be known at compilation timetype_as_string(&&a[..])
can still be called since these are simply references.
Compatibility
fn func(arg: {dst}) {
println!("{:?}", arg);
}
fn main() {
let a: [u8; 3] = [1, 2, 3];
func({src});
}
So, which values can be inserted for {src}
and {dst}
?
src ↓ \ dst → | [u8; 3] |
[u8] |
&[u8; 3] |
&[u8] |
---|---|---|---|---|
|
yes |
no, slice cannot be a parameter type |
no, not a reference |
no, not a reference |
|
no, slice is not an array |
no, slice cannot be a parameter type |
no, not a reference |
no, not a reference |
|
no, not an array, but reference |
no, slice cannot be a parameter type |
yes |
yes, length is dropped |
|
no, not an array, but reference |
no, slice cannot be a parameter type |
no, slice not array; lacking length |
yes |
Conclusion
Arrays are containers with a length. If you loose its length, you have a slice, which is almost unusable. But for both types, you can always take references which work intuitively.