]> git.lizzy.rs Git - rust.git/blob - src/doc/trpl/more-strings.md
Auto merge of #23678 - richo:check-flightcheck, r=alexcrichton
[rust.git] / src / doc / trpl / more-strings.md
1 % More Strings
2
3 Strings are an important concept to master in any programming language. If you
4 come from a managed language background, you may be surprised at the complexity
5 of string handling in a systems programming language. Efficient access and
6 allocation of memory for a dynamically sized structure involves a lot of
7 details. Luckily, Rust has lots of tools to help us here.
8
9 A **string** is a sequence of unicode scalar values encoded as a stream of
10 UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences.
11 Additionally, strings are not null-terminated and can contain null bytes.
12
13 Rust has two main types of strings: `&str` and `String`.
14
15 # `&str`
16
17 The first kind is a `&str`. This is pronounced a 'string slice'.
18 String literals are of the type `&str`:
19
20 ```
21 let string = "Hello there.";
22 ```
23
24 Like any Rust reference, string slices have an associated lifetime. A string
25 literal is a `&'static str`.  A string slice can be written without an explicit
26 lifetime in many cases, such as in function arguments. In these cases the
27 lifetime will be inferred:
28
29 ```
30 fn takes_slice(slice: &str) {
31     println!("Got: {}", slice);
32 }
33 ```
34
35 Like vector slices, string slices are simply a pointer plus a length. This
36 means that they're a 'view' into an already-allocated string, such as a
37 string literal or a `String`.
38
39 ## `str`
40
41 You may occasionally see references to a `str` type, without the `&`. While
42 this type does exist, it’s not something you want to use yourself. Sometimes,
43 people confuse `str` for `String`, and write this:
44
45 ```rust
46 struct S {
47     s: str,
48 }
49 ```
50
51 This leads to ugly errors:
52
53 ```text
54 error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277]
55 note: `str` does not have a constant size known at compile-time
56 ```
57
58 Instead, this `struct` should be
59
60 ```rust
61 struct S {
62     s: String,
63 }
64 ```
65
66 So let’s talk about `String`s.
67
68 # `String`
69
70 A `String` is a heap-allocated string. This string is growable, and is
71 also guaranteed to be UTF-8. `String`s are commonly created by
72 converting from a string slice using the `to_string` method.
73
74 ```
75 let mut s = "Hello".to_string();
76 println!("{}", s);
77
78 s.push_str(", world.");
79 println!("{}", s);
80 ```
81
82 A reference to a `String` will automatically coerce to a string slice:
83
84 ```
85 fn takes_slice(slice: &str) {
86     println!("Got: {}", slice);
87 }
88
89 fn main() {
90     let s = "Hello".to_string();
91     takes_slice(&s);
92 }
93 ```
94
95 You can also get a `&str` from a stack-allocated array of bytes:
96
97 ```
98 use std::str;
99
100 let x: &[u8] = &[b'a', b'b'];
101 let stack_str: &str = str::from_utf8(x).unwrap();
102 ```
103
104 # Best Practices
105
106 ## `String` vs. `&str`
107
108 In general, you should prefer `String` when you need ownership, and `&str` when
109 you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
110 and `T` vs `&T` in general.
111
112 This means starting off with this:
113
114 ```{rust,ignore}
115 fn foo(s: &str) {
116 ```
117
118 and only moving to this:
119
120 ```{rust,ignore}
121 fn foo(s: String) {
122 ```
123
124 if you have good reason. It's not polite to hold on to ownership you don't
125 need, and it can make your lifetimes more complex.
126
127 ## Generic functions
128
129 To write a function that's generic over types of strings, use `&str`.
130
131 ```
132 fn some_string_length(x: &str) -> usize {
133     x.len()
134 }
135
136 fn main() {
137     let s = "Hello, world";
138
139     println!("{}", some_string_length(s));
140
141     let s = "Hello, world".to_string();
142
143     println!("{}", some_string_length(&s));
144 }
145 ```
146
147 Both of these lines will print `12`.
148
149 ## Indexing strings
150
151 You may be tempted to try to access a certain character of a `String`, like
152 this:
153
154 ```{rust,ignore}
155 let s = "hello".to_string();
156
157 println!("{}", s[0]);
158 ```
159
160 This does not compile. This is on purpose. In the world of UTF-8, direct
161 indexing is basically never what you want to do. The reason is that each
162 character can be a variable number of bytes. This means that you have to iterate
163 through the characters anyway, which is an O(n) operation.
164
165 There's 3 basic levels of unicode (and its encodings):
166
167 - code units, the underlying data type used to store everything
168 - code points/unicode scalar values (char)
169 - graphemes (visible characters)
170
171 Rust provides iterators for each of these situations:
172
173 - `.bytes()` will iterate over the underlying bytes
174 - `.chars()` will iterate over the code points
175 - `.graphemes()` will iterate over each grapheme
176
177 Usually, the `graphemes()` method on `&str` is what you want:
178
179 ```
180 # #![feature(unicode)]
181 let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
182
183 for l in s.graphemes(true) {
184     println!("{}", l);
185 }
186 ```
187
188 This prints:
189
190 ```text
191
192 n͈̰̎
193 i̙̮͚̦
194 c͚̉
195 o̼̩̰͗
196 d͔̆̓ͥ
197
198 ```
199
200 Note that `l` has the type `&str` here, since a single grapheme can consist of
201 multiple codepoints, so a `char` wouldn't be appropriate.
202
203 This will print out each visible character in turn, as you'd expect: first `u͔`, then
204 `n͈̰̎`, etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`:
205
206 ```
207 let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
208
209 for l in s.chars() {
210     println!("{}", l);
211 }
212 ```
213
214 This prints:
215
216 ```text
217 u
218 ͔
219 n
220 ̎
221 ͈
222 ̰
223 i
224 ̙
225 ̮
226 ͚
227 ̦
228 c
229 ̉
230 ͚
231 o
232 ͗
233 ̼
234 ̩
235 ̰
236 d
237 ̆
238 ̓
239 ͥ
240 ͔
241 e
242 ́
243 ```
244
245 You can see how some of them are combining characters, and therefore the output
246 looks a bit odd.
247
248 If you want the individual byte representation of each codepoint, you can use
249 `.bytes()`:
250
251 ```
252 let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
253
254 for l in s.bytes() {
255     println!("{}", l);
256 }
257 ```
258
259 This will print:
260
261 ```text
262 117
263 205
264 148
265 110
266 204
267 142
268 205
269 136
270 204
271 176
272 105
273 204
274 153
275 204
276 174
277 205
278 154
279 204
280 166
281 99
282 204
283 137
284 205
285 154
286 111
287 205
288 151
289 204
290 188
291 204
292 169
293 204
294 176
295 100
296 204
297 134
298 205
299 131
300 205
301 165
302 205
303 148
304 101
305 204
306 129
307 ```
308
309 Many more bytes than graphemes!
310
311 # `Deref` coercions
312
313 References to `String`s will automatically coerce into `&str`s. Like this:
314
315 ```
316 fn hello(s: &str) {
317    println!("Hello, {}!", s);
318 }
319
320 let slice = "Steve";
321 let string = "Steve".to_string();
322
323 hello(slice);
324 hello(&string);
325 ```