Use Case for Box<str> and String

Box<str> and String seem to be very similar types. When should I use each? I am particularly concerned with the case of copying the contents of an &str that will soon go out of scope.

Both Box<str> and String provide ownership over a string type. Both types copy a str from the stack to the heap (via String's interior use of Vec<u8>) when create from an &str, and both provide access to methods on &str via Deref Coercion. As far as I can tell, the only differences between Box<str> and String is that String defines a bunch more methods.

Am I missing anything, and when should I use Box<str> and when should I use String?

7 Likes

String can grow by resizing itself. Can Box<str> do that?

1 Like

I would know of no good reason to use Box<str> over String.

As far as I know there is exactly one reason to use Box<str> over String. On my computer:

use std::mem::size_of;

fn main() {
    println!("{}", size_of::<Box<str>>()); // 16
    println!("{}", size_of::<String>()); // 24
}

String stores pointer+length+capacity while Box<str> stores pointer+size. The capacity allows String to append efficiently. The compiler uses Box<str> as an optimization when it has a massive number of immutable strings so size matters, for example the string interner:

https://github.com/rust-lang/rust/blob/7846610470392abc3ab1470853bbe7b408fe4254/src/libsyntax/symbol.rs#L82-L85

21 Likes

Thanks a lot -- that makes sense.

My only other question is this -- if a Box<str> has only a pretty niche use case, then why does String even have an .into_boxed_str() method? Is it just because there's no other way to get a Box<str> from a &str?

2 Likes

And FWIW, you can make the exact same argument for Vec<T> versus Box<[T]>.

14 Likes