9 ms·
It's unfortunate that strings are badly named in rust. They got that better with Path and PathBuf. str is fixed size, like a Java String String is growable, l
by sirwhinesalot 4y ago
It's unfortunate that strings are badly named in rust. They got that better with Path and PathBuf.
str is fixed size, like a Java String
String is growable, like a Java StringBuilder
After that, we get into memory ownership, with &str not owning memory, and Box<str> owning memory, but you rarely need the latter, so it's really &str vs String that you need to care about.
EDIT: changed immutable to fixed and mutable to growable to better reflect the real difference, though typically you almost always use immutable &str and &mut String. I thank the commenters below for pointing it out, I don't want to make the problem even more confusing than it already is.
- marcosdumay 4y ago> but you rarely need the latter AFAIK, it's because people go with String when what they actually mean is Box<str>. Since they have similar costs, nobody ever sees the need to change it, and the String type does have a much better name. But the need is there all the time. People just satisfy it differently.
- sirwhinesalot 4y agoI think it's mainly because unlike Java, where a StringBuilder is effectively an optimisation over concatenating Strings, in Rust managing that memory would be a total pain, so you tend to keep the mutable thing around. Once that happens, Box<str> becomes kinda unnecessary. There are many cases where it would be the correct type, for example reading from a file in a read-only manner, but most of the time you're going to be doing something to that text, so it makes more sense to just load it up as a String already and avoid the unnecessary copy. Either way, it's mostly a naming problem. &str/String sucks :(
- afdbcreid 4y agoIt's not just the naming: I prefer String if I don't care about the data structure size, since converting a String to Box<str> can be costly (allocation and copy if the capacity isn't exact) and carrying a capacity is free pretty much all of the time.
- Arnavion 4y agoString used to be StrBuf first. The rename to String was intentional because String was the more commonly known name in other languages. https://rust-lang.github.io/rfcs/0060-rename-strbuf.html https://rust-lang.github.io/rfcs/0060-rename-strbuf.html
- lifthrasiir 4y agoNote that this is a very old RFC and doesn't have much context and discussion compared to later RFCs. It is worthwhile to read the actual discussion happened [1]. [1] https://github.com/rust-lang/rfcs/pull/60 https://github.com/rust-lang/rfcs/pull/60
- sirwhinesalot 4y agoUnfortunately, judging by the fact so many people are still confused about it, it was a mistake. Having a shorthand for something (str) and that thing (String) be different things was dumb, and someone brought that up in the discussion at the time but I guess hindsight is 20/20. C++ has std::string and std::string_view which makes a loads more sense. Java and C# have StringBuilder and String. Go has strings.Builder and string. Objective-C/Cocoa has and NSMutableString and NSString. ADA has Unbounded_String, Bounded_String and Fixed_String for different use cases. Rust has by far the worst naming.
- kzrdude 4y agoI guess C++ has the best names after all, Rust should have emulated those (except it couldn't - string_view came after Rust and maybe even was inspired by Rust.)
- cmrdporcupine 4y agoChromium's C++ StringPiece dates back to at least 2012, and pretty sure Google had something similar (I forget the original name) to it in Google3's C++ base library which became abseil's string_view before that even. And Boost had string_ref at least as far back as 2013. https://chromium.googlesource.com/chromium/src/base/+/master/strings/string_piece.h https://chromium.googlesource.com/chromium/src/base/+/master... https://github.com/abseil/abseil-cpp/blob/master/absl/strings/string_view.h https://github.com/abseil/abseil-cpp/blob/master/absl/string... https://github.com/steinwurf/boost/commits/master/boost/utility/string_ref.hpp https://github.com/steinwurf/boost/commits/master/boost/util... All of this is arguably before Rust's influence would have been anything to speak of.
- Blikkentrekker 4y agoI find that this explanation does not do justice The important part is that `str` is a dynamically sized type as it's called. What it is is simply a region of memory, of any size, containing UTF8. Since it is dynamically sized various constraints are placed onto it which in practice come down to that it can only really be passed around at runtime by being behind a pointer and is hard to directly put on the stack. `String` is three words, two words are æquivalent to a “fat pointer” to a `str`, as in one word for the address, and the other for the size, which is how Rust deals with dynamically sized types in general, and the third word denotes the capacity of memory allocated to the `String` which it uses to know when to reallocate. `str` is neither mutable nor immutable which isn't part of it's type, `&str` is immutable, and `&mut str` is mutable. It's perfectly possible in Rust to mutate a `str` if one obtains a mutable, or perhaps better called exclusive reference to it somehow, but the mutations that can be performed are very limited since the size cannot easily grow. This is where `String` comes in, which guarantees that the space after the `str` pointed to it, the size of it's “capacity” third word is not used by anything else, and thus it can grow more easily by manipulations. There are some limited mutation methods on `&mut str` in Rust, such as `make_ascii_uppercase`, which converts all lowercase ascii letters to uppercase, which is perfectly fine, since this operation is guaranteed to not ever increase the size of the `str`, but with unicode such a guarantee no longer applies and one needs a `String`. That being said, yes, I would have favored for `String` to be called `StrBuf`, and `Vec` `SliceBuf` instead.
- sirwhinesalot 4y agoSure, if you want to be truly specific about it and not do a Java analogy ;)
- _0w8t 4y agoString in Rust is very similar to std::string in C++, while str is std::string_view except it is safe to use. StringBuffer in Java is not like String in Rust. In particular, one cannot pass StringBuffer in Java to a function taking String, while both Rust and C++ allow to implicitly convert the string backed by a heap into the corresponding read-only view.
- sirwhinesalot 4y agoStrings in Java own their memory, they aren't views, they're closer to Box<str>. That's why you can't implicitly convert a StringBuilder into one. I know this, I'm not the one you need to explain it too, it's Rust newbies. So many problems would have been avoided with Str/StrBuf or StrView/Str, but now the ship has sailed.
- rrobukef 4y agoString in Java share their memory with other substrings of the same allocation. They are views.
- cesarb 4y agoIIRC, that used to be the case, but recent Java releases changed it so that memory is no longer shared with substrings. The former behavior could cause some extreme memory leaks (unless you were very careful to always manually duplicate each substring); a one-character substring could keep a multi-megabyte memory allocation alive. See for instance https://stackoverflow.com/questions/33893655/string-substring-making-a-copy-of-the-underlying-char-value https://stackoverflow.com/questions/33893655/string-substrin... which discusses this issue.
- masklinn 4y agoThat was changed years ago (the slicing optimisation was removed in Java 7 or something) because it caused too many memory leaks. It was also a (bad) optimisation, it was never part of the langage model or semantics.
- 4y ago
- nicoburns 4y agoPersonally I'd prefer String/StringView (and potentially Path and PathView), but I guess that ship has sailed.
- bmacho 4y agoWhy StringView? What is that supposed to mean?
- aliceryhl 4y agoThe difference has to do with ownership, and it has nothing to do with mutability. For both types, you can mutate them given a mutable refence, and you can't given an immutable reference. For an example, an `&mut str` can be modified via various methods such as make_ascii_uppercase.
- sirwhinesalot 4y agoNope, not ownership either, Box<str> and String both own their memory, the different is fixed size vs growable :) But you're right, I edited my post to reflect this, the Java analogy is pretty strained as it is.
- Macha 4y agoI believe the parent poster was comparing &str and String, not Box<str> and String.
- sirwhinesalot 4y agoYeah in my original post (before the edit) I made a similar simplification with immutable vs mutable (since that's how they are commonly used), but the correct distinction is str vs String. You can have &str and &String and you can have &mut str and &mut String, and Box<str> and String. All cases exist.