as, to and into methods in rust
15 July 2020. Estimated reading time: 3 min.
Rust standard library types frequently have methods with names that look like
as_something
, to_something
, or into_something
. Clearly the difference
between "as", "to" and "into" is intentional, and I realized I didn't know why.
So let's pick String
, and take a closer look at the as/to/into methods that
are available.
pub fn to_lowercase(&self) -> String;
pub fn into_bytes(self) -> Vec<u8>;
pub fn as_bytes(&self) -> &[u8];
In the to_lowercase
method, it's clear from the function name that it may
need to produce new characters, and we also see that it only borrows the
string, but returns a new owned string. Clearly then it's allocating a new
string, and filling it with characters either copied or converted from the
source string.
If we check the source code, we see that's indeed the case.
pub fn to_lowercase(&self) -> String {
let mut s = String::with_capacity(self.len());
for (i, c) in self[..].char_indices() {
// ... push chars into `s`
}
return s;
}
The into_bytes
method is similar in that it too returns an owned value.
However, it's called "into" and, unlike "to", the source string is moved. We
can make an educated guess that underlying representation is reused by the
Vec
, otherwise it would make more sense to make this a "to" method, and
preserve the original string.
In fact, String
is implemented over a Vec
, so this method merely consumes
the String
wrapper and returns the underlying Vec
.
pub fn into_bytes(self) -> Vec<u8> {
self.vec
}
Finally, as_bytes
takes and returns a reference. It's a conversion, but a
lightweight one, in which the underlying data in memory is shared by both
source and destination values.
Checking the source code we see that it too uses the underlying
Vec
, but returns a slice from it, instead of the Vec
itself.
pub fn as_bytes(&self) -> &[u8] {
&self.vec
}
So, what can we extrapolate from this?
"As" methods perform lightweight conversions, and both take and return a reference to the same underlying data in memory. No cloning involved.
"To" methods perform conversions that require copying the underlying data,
sometimes just because the return type is useful because it's owned, like
when calling to_string()
on a &str
.
And "Into" methods are suitable for conversions that require taking ownership of the source value to be efficient and avoid duplication of data. They are also aptly named: they are "to" methods that take in the original value.
Last updated: 15 July 2020.