mirror of
https://github.com/rust-lang-cn/book-cn.git
synced 2025-01-23 23:50:25 +08:00
Small wording tweaks, mostly removing 'you'
This commit is contained in:
parent
b168c614a2
commit
6bef3b89cf
@ -7,10 +7,10 @@ different capabilities and costs, and choosing an appropriate one for the
|
|||||||
situation you're in is a skill you'll develop over time. In this chapter, we'll
|
situation you're in is a skill you'll develop over time. In this chapter, we'll
|
||||||
go over three collections which are used very often in Rust programs:
|
go over three collections which are used very often in Rust programs:
|
||||||
|
|
||||||
* A *Vector* allows you to store a variable number of values next to each other.
|
* A *Vector* allows us to store a variable number of values next to each other.
|
||||||
* A *String* is a collection of characters. We've seen `String` before, but
|
* A *String* is a collection of characters. We've seen `String` before, but
|
||||||
we'll talk about it in depth now.
|
we'll talk about it in depth now.
|
||||||
* A *HashMap* allows you to associate a value with a particular key.
|
* A *HashMap* allows us to associate a value with a particular key.
|
||||||
|
|
||||||
There are more specialized variants of each of these data structures for
|
There are more specialized variants of each of these data structures for
|
||||||
particular situations, but these are the most fundamental and common. We're
|
particular situations, but these are the most fundamental and common. We're
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
## Vectors
|
## Vectors
|
||||||
|
|
||||||
The first type we'll look at is `Vec<T>`, also known as a *vector*. Vectors
|
The first type we'll look at is `Vec<T>`, also known as a *vector*. Vectors
|
||||||
allow you to store more than one value in a single data structure that puts all
|
allow us to store more than one value in a single data structure that puts all
|
||||||
the values next to each other in memory.
|
the values next to each other in memory.
|
||||||
|
|
||||||
### Creating a New Vector
|
### Creating a New Vector
|
||||||
|
|
||||||
To create a new vector, you can call the `new` function:
|
To create a new vector, we can call the `new` function:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let v: Vec<i32> = Vec::new();
|
let v: Vec<i32> = Vec::new();
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll note that we added a type annotation here. Because we don't actually do
|
Note that we added a type annotation here. Since we don't actually do
|
||||||
anything with the vector, Rust doesn't know what kind of elements we intend to
|
anything with the vector, Rust doesn't know what kind of elements we intend to
|
||||||
store. This is an important point. Vectors are homogenous: they may store many
|
store. This is an important point. Vectors are homogenous: they may store many
|
||||||
values, but those values must all be the same type. Vectors are generic over
|
values, but those values must all be the same type. Vectors are generic over
|
||||||
the type you store inside them (we'll talk about Generics more throroughly in
|
the type stored inside them (we'll talk about Generics more throroughly in
|
||||||
Chapter XX), and the angle brackets here tell Rust that this vector will hold
|
Chapter XX), and the angle brackets here tell Rust that this vector will hold
|
||||||
elements of the `i32` type.
|
elements of the `i32` type.
|
||||||
|
|
||||||
That said, in real code, you very rarely need to do this type annotation since
|
That said, in real code, we very rarely need to do this type annotation since
|
||||||
Rust can infer the type of value we want to store once we insert values. Let's
|
Rust can infer the type of value we want to store once we insert values. Let's
|
||||||
look at how to modify a vector next.
|
look at how to modify a vector next.
|
||||||
|
|
||||||
@ -100,10 +100,10 @@ let does_not_exist = v.get(100);
|
|||||||
|
|
||||||
With the `[]`s, Rust will cause a `panic!`. With the `get` method, it will
|
With the `[]`s, Rust will cause a `panic!`. With the `get` method, it will
|
||||||
instead return `None` without `panic!`ing. Deciding which way to access
|
instead return `None` without `panic!`ing. Deciding which way to access
|
||||||
elements in a vector depends on whether you consider an attempted access past
|
elements in a vector depends on whether we consider an attempted access past
|
||||||
the end of the vector to be an error, in which case you would want the `panic!`
|
the end of the vector to be an error, in which case we'd want the `panic!`
|
||||||
behavior, or whether this will happen occasionally under normal circumstances
|
behavior, or whether this will happen occasionally under normal circumstances
|
||||||
and your code will have logic to handle getting `Some(&element)` or `None`.
|
and our code will have logic to handle getting `Some(&element)` or `None`.
|
||||||
|
|
||||||
Once we have a valid reference, the borrow checker will enforce the ownership
|
Once we have a valid reference, the borrow checker will enforce the ownership
|
||||||
and borrowing rules we covered in Chapter 4 in order to ensure this and other
|
and borrowing rules we covered in Chapter 4 in order to ensure this and other
|
||||||
|
@ -9,16 +9,16 @@ Strings are a common place for new Rustaceans to get stuck. This is due to a
|
|||||||
combination of three things: Rust's propensity for making sure to expose
|
combination of three things: Rust's propensity for making sure to expose
|
||||||
possible errors, strings being a more complicated data structure than many
|
possible errors, strings being a more complicated data structure than many
|
||||||
programmers give them credit for, and UTF-8. These things combine in a way that
|
programmers give them credit for, and UTF-8. These things combine in a way that
|
||||||
can seem difficult when you're used to other languages.
|
can seem difficult coming from other languages.
|
||||||
|
|
||||||
Before we can dig into those things, we need to talk about what exactly we even
|
Before we can dig into those aspects, we need to talk about what exactly we
|
||||||
mean by the word 'string'. Rust-the-language has only one string type: `&str`.
|
even mean by the word 'string'. Rust actually only has one string type in the
|
||||||
We talked about these string slices in Chapter 4: they're a reference to some
|
core language itself: `&str`. We talked about these string slices in Chapter 4:
|
||||||
UTF-8 encoded string data stored somewhere else. String literals, for example,
|
they're a reference to some UTF-8 encoded string data stored somewhere else.
|
||||||
are stored in the binary output of your program, and are therefore string
|
String literals, for example, are stored in the binary output of the program,
|
||||||
slices.
|
and are therefore string slices.
|
||||||
|
|
||||||
Rust's standard library also provides a type called `String`. This is a
|
Rust's standard library is what provides the type called `String`. This is a
|
||||||
growable, mutable, owned, UTF-8 encoded string type. When Rustaceans talk about
|
growable, mutable, owned, UTF-8 encoded string type. When Rustaceans talk about
|
||||||
'strings' in Rust, they usually mean "`String` and `&str`". This chapter is
|
'strings' in Rust, they usually mean "`String` and `&str`". This chapter is
|
||||||
largely about `String`, and these two types are used heavily in Rust's standard
|
largely about `String`, and these two types are used heavily in Rust's standard
|
||||||
@ -26,12 +26,12 @@ library. Both `String` and string slices are UTF-8 encoded.
|
|||||||
|
|
||||||
Rust's standard library also includes a number of other string types, such as
|
Rust's standard library also includes a number of other string types, such as
|
||||||
`OsString`, `OsStr`, `CString`, and `CStr`. Library crates may provide even
|
`OsString`, `OsStr`, `CString`, and `CStr`. Library crates may provide even
|
||||||
more options for storing string data. As you can see from the `*String`/`*Str`
|
more options for storing string data. Similarly to the `*String`/`*Str` naming,
|
||||||
naming, they often provide an owned and borrowed variant, just like
|
they often provide an owned and borrowed variant, just like `String`/`&str`.
|
||||||
`String`/`&str`. These string types may store different encodings or be
|
These string types may store different encodings or be represented in memory in
|
||||||
represented in memory in a different way, for example. We won't be talking
|
a different way, for example. We won't be talking about these other string
|
||||||
about these other string types in this chapter; see their API documentation for
|
types in this chapter; see their API documentation for more about how to use
|
||||||
more about how to use them and when each is appropriate.
|
them and when each is appropriate.
|
||||||
|
|
||||||
### Creating a New String
|
### Creating a New String
|
||||||
|
|
||||||
@ -42,8 +42,8 @@ starting with creating one. Similarly, `String` has `new`:
|
|||||||
let s = String::new();
|
let s = String::new();
|
||||||
```
|
```
|
||||||
|
|
||||||
Often, you have some initial data that you'd like to start the string off with.
|
Often, we'll have some initial data that we'd like to start the string off with.
|
||||||
For that, there's the `.to_string()` method:
|
For that, there's the `to_string` method:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let data = "initial contents";
|
let data = "initial contents";
|
||||||
@ -54,13 +54,13 @@ let s = data.to_string();
|
|||||||
let s = "initial contents".to_string();
|
let s = "initial contents".to_string();
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll also see this form sometimes:
|
This form is equivalent to using `to_string`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let s = String::from("Initial contents");
|
let s = String::from("Initial contents");
|
||||||
```
|
```
|
||||||
|
|
||||||
Because strings are used for so many things, there are many different generic
|
Since strings are used for so many things, there are many different generic
|
||||||
APIs that make sense for strings. There are a lot of options, and some of them
|
APIs that make sense for strings. There are a lot of options, and some of them
|
||||||
can feel redundant because of this, but they all have their place! In this
|
can feel redundant because of this, but they all have their place! In this
|
||||||
case, `String::from` and `.to_string` end up doing the exact same thing, so
|
case, `String::from` and `.to_string` end up doing the exact same thing, so
|
||||||
@ -68,8 +68,8 @@ which you choose is a matter of style. Some people use `String::from` for
|
|||||||
literals, and `.to_string` for variable bindings. Most Rust style is pretty
|
literals, and `.to_string` for variable bindings. Most Rust style is pretty
|
||||||
uniform, but this specific question is one of the most debated.
|
uniform, but this specific question is one of the most debated.
|
||||||
|
|
||||||
Don't forget that strings are UTF-8 encoded, so you can include any
|
Remember that strings are UTF-8 encoded, so we can include any properly encoded
|
||||||
properly encoded data in them:
|
data in them:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let hello = "السلام عليكم";
|
let hello = "السلام عليكم";
|
||||||
@ -91,7 +91,7 @@ A `String` can be changed and can grow in size, just like a `Vec` can.
|
|||||||
|
|
||||||
#### Push
|
#### Push
|
||||||
|
|
||||||
You can grow a `String` by using the `push_str` method to append another
|
We can grow a `String` by using the `push_str` method to append another
|
||||||
string:
|
string:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -110,7 +110,7 @@ s.push('l');
|
|||||||
|
|
||||||
`s` will contain "lol" after this point.
|
`s` will contain "lol" after this point.
|
||||||
|
|
||||||
You can make any `String` contain the empty string with the `clear` method:
|
We can make any `String` contain the empty string with the `clear` method:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut s = String::from("Noooooooooooooooooooooo!");
|
let mut s = String::from("Noooooooooooooooooooooo!");
|
||||||
@ -121,7 +121,7 @@ Now `s` will be the empty string, "".
|
|||||||
|
|
||||||
#### Concatenation
|
#### Concatenation
|
||||||
|
|
||||||
Often, you'll want to combine two strings together. One way is to use the `+`
|
Often, we'll want to combine two strings together. One way is to use the `+`
|
||||||
operator:
|
operator:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -144,11 +144,11 @@ signature of the method would be if `add` was defined specifically for
|
|||||||
`String`. This signature gives us the clues we need in order to understand the
|
`String`. This signature gives us the clues we need in order to understand the
|
||||||
tricky bits of `+`.
|
tricky bits of `+`.
|
||||||
|
|
||||||
First of all, you'll notice that `s2` has an `&`. This is because of the `s`
|
First of all, `s2` has an `&`. This is because of the `s` argument in the `add`
|
||||||
argument in the `add` function: you can only add a `&str` to a `String`, you
|
function: we can only add a `&str` to a `String`, we can't add two `String`s
|
||||||
can't add two `String`s together. Remember back in Chapter 4 when we talked
|
together. Remember back in Chapter 4 when we talked about how `&String` will
|
||||||
about how `&String` will coerce to `&str`: we write `&s2` so that the `String`
|
coerce to `&str`: we write `&s2` so that the `String` will coerce to the proper
|
||||||
will coerce to the proper type, `&str`.
|
type, `&str`.
|
||||||
|
|
||||||
Secondly, `add` takes ownership of `self`, which we can tell because `self`
|
Secondly, `add` takes ownership of `self`, which we can tell because `self`
|
||||||
does *not* have an `&` in the signature. This means `s1` in the above example
|
does *not* have an `&` in the signature. This means `s1` in the above example
|
||||||
@ -159,7 +159,7 @@ new one, this statement actually takes ownership of `s1`, appends a copy of
|
|||||||
like it's making a lot of copies, but isn't: the implementation is more
|
like it's making a lot of copies, but isn't: the implementation is more
|
||||||
efficient than copying.
|
efficient than copying.
|
||||||
|
|
||||||
If you need to concatenate multiple strings, this behavior of `+` gets
|
If we need to concatenate multiple strings, this behavior of `+` gets
|
||||||
unwieldy:
|
unwieldy:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -245,7 +245,7 @@ let answer = &h[0];
|
|||||||
```
|
```
|
||||||
|
|
||||||
What should the value of `answer` be? Should it be `З`, the first letter? When
|
What should the value of `answer` be? Should it be `З`, the first letter? When
|
||||||
you encode `З` in UTF-8, the first byte is `208`, and the second is `151`. So
|
encoded in UTF-8, the first byte of `З` is `208`, and the second is `151`. So
|
||||||
should `answer` be `208`? `208` is not a valid character on its own, though.
|
should `answer` be `208`? `208` is not a valid character on its own, though.
|
||||||
Plus, for latin letters, this would not return the answer most people would
|
Plus, for latin letters, this would not return the answer most people would
|
||||||
expect: `&"hello"[0]` would then return `104`, not `h`.
|
expect: `&"hello"[0]` would then return `104`, not `h`.
|
||||||
@ -277,8 +277,8 @@ get this:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Four elements! It turns out that even within 'grapheme cluster', there are
|
Four elements! It turns out that even within 'grapheme cluster', there are
|
||||||
multiple ways of grouping things. Have we convinced you strings are actually
|
multiple ways of grouping things. Convinced that strings are actually really
|
||||||
really complicated yet?
|
complicated yet?
|
||||||
|
|
||||||
Another reason that indexing into a `String` to get a character is not available
|
Another reason that indexing into a `String` to get a character is not available
|
||||||
is that indexing operations are expected to always be fast. This isn't possible
|
is that indexing operations are expected to always be fast. This isn't possible
|
||||||
@ -292,7 +292,7 @@ we cannot directly do this.
|
|||||||
### Slicing Strings
|
### Slicing Strings
|
||||||
|
|
||||||
However, indexing the bytes of a string is very useful, and is not expected to
|
However, indexing the bytes of a string is very useful, and is not expected to
|
||||||
be fast. While you can't use `[]` with a single number, you _can_ use `[]` with
|
be fast. While we can't use `[]` with a single number, we _can_ use `[]` with
|
||||||
a range to create a string slice from particular bytes:
|
a range to create a string slice from particular bytes:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -35,7 +35,7 @@ of type `i32` and values of type `&str`. Like vectors, HashMaps are homogenous:
|
|||||||
all of the keys must have the same type, and all of the values must have the
|
all of the keys must have the same type, and all of the values must have the
|
||||||
same type.
|
same type.
|
||||||
|
|
||||||
If you have a vector of tuples, you can convert it into a HashMap with the
|
If we have a vector of tuples, we can convert it into a HashMap with the
|
||||||
`collect` method. The first element in each tuple will be the key, and the
|
`collect` method. The first element in each tuple will be the key, and the
|
||||||
second element will be the value:
|
second element will be the value:
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ This will print:
|
|||||||
|
|
||||||
#### Overwriting a Value
|
#### Overwriting a Value
|
||||||
|
|
||||||
If you insert a key and a value, then insert that key with a different value, the value associated with that key will be replaced. Even though this code calls `insert` twice, the HashMap will only contain one key/value pair, since we're inserting with the key `1` both times:
|
If we insert a key and a value, then insert that key with a different value, the value associated with that key will be replaced. Even though this code calls `insert` twice, the HashMap will only contain one key/value pair, since we're inserting with the key `1` both times:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -176,7 +176,7 @@ println!("{:?}", map);
|
|||||||
The `or_insert` method on `Entry` does exactly this: returns the value for the
|
The `or_insert` method on `Entry` does exactly this: returns the value for the
|
||||||
`Entry`'s key if it exists, and if not, inserts its argument as the new value
|
`Entry`'s key if it exists, and if not, inserts its argument as the new value
|
||||||
for the `Entry`'s key and returns that. This is much cleaner than writing the
|
for the `Entry`'s key and returns that. This is much cleaner than writing the
|
||||||
logic yourself, and in addition, plays more nicely with the borrow checker.
|
logic ourselves, and in addition, plays more nicely with the borrow checker.
|
||||||
|
|
||||||
This code will print `{1: "hello", 2: "world"}`. The first call to `entry` will
|
This code will print `{1: "hello", 2: "world"}`. The first call to `entry` will
|
||||||
insert the key `2` with the value "world", since `2` doesn't have a value
|
insert the key `2` with the value "world", since `2` doesn't have a value
|
||||||
|
Loading…
Reference in New Issue
Block a user