Use Case for Box<str> and String


#1

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?


#2

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


#3

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


#4

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:


#5

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?


#6

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