Converting {String, &str} into Box<str>

For String to Box<str> conversion, there are two options:

  1. Calling into() or from() as Box<str> implements From<String>
  2. Calling into_boxed_str()

But, for &str to Box<str> conversion, there is only one option:

  1. Calling into() or from() as Box<str> implements From<&str>

So, what's the reasoning behind String having a separate (redundant?) function for converting into Box<str>?

The inherent functions came first.[1] Why an inherent version for str wasn't included, I couldn't say -- perhaps just no one thought to do so. Going from &str to String to Box<str> probably does the same thing, but I didn't find any guarantees of that upon a quick browse. [2]

  1. Trait versions: one and two. ↩︎

  2. The requisite guarantee is that any particular method of going from &str to String results in a String with no excess capacity. ↩︎

1 Like

I personally prefer to long, verbose functions (e.g. to_path_buf()) over into, to_owned etc. because it's a little more obvious to me what's happening. I guess having multiple pathways to get what you want is good, though.


TL;DR: Slice ([T]) does not have such inherent method, so does str. Maybe that is why they look asymmetric.
However I don't know why slice does not have such method.

Maybe this.

Did some web search and git blame, but I don't get enough info about things from pre-1.0 Rust (especially slice and box).
I've heard that Rust had reference syntax and box syntax different from the current one, and even that it had GC at some point (and removed later but before 1.0), so possibly many things including slice and box may differ from today's Rust...

Before 1.4.0 era, <Vec<T>>::into_boxed_slice and <Box<[T]>>::into_vec had already been available.

Maybe to make string types API more coherent to boxed slices (i.e. to make String-Box<str> more similar to Vec<T>-Box<[T]>), <Box<str>>::into_string and String::into_boxed_str (String::into_boxed_slice when proposed) is added since 1.4.0.

So, Vec-Box relationship for string types is implemented first.
Vec has inherent method to create Box, so does String.

From/Into traits were implemented later. (maybe to make them more comprehensive API?)
Since 1.17.0, From<&[T]> for Box<[T]> and From<&str> for Box<str> were added.
Since 1.18.0 (and 1.20.0), Vec<T><->Box[T] and String<->Box<str> were added.

My conclusion (not guaranteed to be true):
Inherent method for str (such as str::into_boxed_str) have not been added since counterpart methods for slice (such as <[T]>::into_boxed_slice) haven't existed.


I guess, you could always write <Box<str> as From<&str>>::from(…) if you want to be verbose and making obvious what's going on.

Because if s.len() == s.capacity(), then String::into_boxed_str is O(1) non-allocating.

&str to Box<str> will always need a new allocation, so there's no point in a separate function to talk about that.

(Meta: Sometimes the value of a function is in having a clearer place to have special behaviour be discoverable and documented. Stuffing everything into From becomes a mess, particularly as the behaviours get more interesting.)