This commit is contained in:
sunface
2022-03-28 22:08:01 +08:00
10 changed files with 85 additions and 74 deletions

View File

@ -37,12 +37,12 @@ fn main() {
```rust,editable ```rust,editable
fn main() { fn main() {
let arr: [i32; 5] = [1, 2, 3, 4, 5]; let arr: [i32; 5] = [1, 2, 3, 4, 5];
// fill the blanks to make the code work // fill the blanks to make the code work
let slice: __ = __; let slice: __ = __;
assert_eq!(slice, &[2, 3, 4]); assert_eq!(slice, &[2, 3, 4]);
println!("Success!") println!("Success!")
} }
``` ```

View File

@ -9,9 +9,9 @@ The type of string literal `"hello, world"` is `&str`, e.g `let s: &str = "hello
// fix error without adding new line // fix error without adding new line
fn main() { fn main() {
let s: str = "hello, world"; let s: str = "hello, world";
println!("Success!") println!("Success!")
} }
``` ```
@ -22,8 +22,8 @@ fn main() {
// fix the error with at least two solutions // fix the error with at least two solutions
fn main() { fn main() {
let s: Box<str> = "hello, world".into(); let s: Box<str> = "hello, world".into();
greetings(s) greetings(s)
} }
fn greetings(s: &str) { fn greetings(s: &str) {
@ -39,13 +39,13 @@ fn greetings(s: &str) {
// fill the blank // fill the blank
fn main() { fn main() {
let mut s = __; let mut s = __;
s.push_str("hello, world"); s.push_str("hello, world");
s.push('!'); s.push('!');
assert_eq!(s, "hello, world!"); assert_eq!(s, "hello, world!");
println!("Success!") println!("Success!")
} }
``` ```
@ -54,7 +54,7 @@ fn main() {
// fix all errors without adding newline // fix all errors without adding newline
fn main() { fn main() {
let s = String::from("hello"); let s = String::from("hello");
s.push(','); s.push(',');
s.push(" world"); s.push(" world");
s += "!".to_string(); s += "!".to_string();
@ -68,13 +68,13 @@ fn main() {
// fill the blank // fill the blank
fn main() { fn main() {
let s = String::from("I like dogs"); let s = String::from("I like dogs");
// Allocate new memory and store the modified string there // Allocate new memory and store the modified string there
let s1 = s.__("dogs", "cats"); let s1 = s.__("dogs", "cats");
assert_eq!(s1, "I like cats"); assert_eq!(s1, "I like cats");
println!("Success!") println!("Success!")
} }
``` ```
@ -102,25 +102,25 @@ Opsite to the seldom using of `str`, `&str` and `String` are used everywhere!
// fix error with at lest two solutions // fix error with at lest two solutions
fn main() { fn main() {
let s = "hello, world"; let s = "hello, world";
greetings(s) greetings(s)
} }
fn greetings(s: String) { fn greetings(s: String) {
println!("{}",s) println!("{}",s)
} }
``` ```
8. 🌟🌟 We can use `String::from` or `to_string` to convert a `&str` to `String` 8. 🌟🌟 We can use `String::from` or `to_string` to convert a `&str` to `String`
```rust,editable ```rust,editable
// use two approaches to fix the error and without adding a new line // use two approaches to fix the error and without adding a new line
fn main() { fn main() {
let s = "hello, world".to_string(); let s = "hello, world".to_string();
let s1: &str = s; let s1: &str = s;
println!("Success!") println!("Success!")
} }
``` ```
@ -256,10 +256,10 @@ You can use [utf8_slice](https://docs.rs/utf8_slice/1.0.0/utf8_slice/fn.slice.ht
```rust ```rust
use utf8_slice; use utf8_slice;
fn main() { fn main() {
let s = "The 🚀 goes to the 🌑!"; let s = "The 🚀 goes to the 🌑!";
let rocket = utf8_slice::slice(s, 4, 5); let rocket = utf8_slice::slice(s, 4, 5);
// Will equal "🚀" // Will equal "🚀"
} }
``` ```

View File

@ -18,10 +18,10 @@ fn main() {
// make it works // make it works
fn main() { fn main() {
let t = ("i", "am", "sunface"); let t = ("i", "am", "sunface");
assert_eq!(t.1, "sunface"); assert_eq!(t.1, "sunface");
println!("Success!") println!("Success!")
} }
``` ```
@ -72,13 +72,13 @@ fn main() {
```rust,editable ```rust,editable
fn main() { fn main() {
// fill the blank, need a few computations here. // fill the blank, need a few computations here.
let (x, y) = sum_multiply(__); let (x, y) = sum_multiply(__);
assert_eq!(x, 5); assert_eq!(x, 5);
assert_eq!(y, 6); assert_eq!(y, 6);
println!("Success!") println!("Success!")
} }
fn sum_multiply(nums: (i32, i32)) -> (i32, i32) { fn sum_multiply(nums: (i32, i32)) -> (i32, i32) {

View File

@ -99,7 +99,8 @@ fn foo() -> i32 {
fn main() { fn main() {
let pointer = foo as *const (); let pointer = foo as *const ();
let function = unsafe { let function = unsafe {
std::mem::transmute::<*const (), fn() -> i32>(pointer) std::mem::transmute::<*const (), fn() -> i32>(pointer)
};
assert_eq!(function(), 0); assert_eq!(function(), 0);
} }
``` ```

View File

@ -1,12 +1,14 @@
# HashMap # HashMap
`HashMap` 默认使用 `SipHash 1-3` 哈希算法,该算法对于抵抗 `HashDos` 攻击非常有效。在性能方面,如果你的 key 是中型大小的,那该算法非常不错,但是如果是小型的 key( 例如整数 )亦或是大型的 key ( 例如字符串 ),那你需要采用社区提供的其它算法来提高性能。 `HashMap` 默认使用 `SipHash 1-3` 哈希算法,该算法对于抵抗 `HashDos` 攻击非常有效。在性能方面,如果你的 key 是中型大小的,那该算法非常不错,但是如果是小型的 key( 例如整数 )亦或是大型的 key ( 例如字符串 ),那你需要采用社区提供的其它算法来提高性能。
哈希表的算法是基于 Google 的 [SwissTable](https://abseil.io/blog/20180927-swisstables),你可以在[这里](https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h)找到 C++ 的实现,同时在 [CppCon talk](https://www.youtube.com/watch?v=ncHmEUmJZf4) 上也有关于算法如何工作的演讲。 哈希表的算法是基于 Google 的 [SwissTable](https://abseil.io/blog/20180927-swisstables),你可以在[这里](https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h)找到 C++ 的实现,同时在 [CppCon talk](https://www.youtube.com/watch?v=ncHmEUmJZf4) 上也有关于算法如何工作的演讲。
### 基本操作 ### 基本操作
1. 🌟🌟 1. 🌟🌟
```rust,editbale ```rust,editable
// 填空并修复错误 // 填空并修复错误
use std::collections::HashMap; use std::collections::HashMap;
@ -37,6 +39,7 @@ fn main() {
``` ```
2. 🌟🌟 2. 🌟🌟
```rust,editable ```rust,editable
use std::collections::HashMap; use std::collections::HashMap;
@ -63,6 +66,7 @@ fn main() {
``` ```
3. 🌟🌟 3. 🌟🌟
```rust,editable ```rust,editable
// 填空 // 填空
@ -95,18 +99,19 @@ fn random_stat_buff() -> u8 {
``` ```
### HashMap key 的限制 ### HashMap key 的限制
任何实现了 `Eq` 和 `Hash` 特征的类型都可以用于 `HashMap` 的 key包括: 任何实现了 `Eq` 和 `Hash` 特征的类型都可以用于 `HashMap` 的 key包括:
- `bool` (虽然很少用到,因为它只能表达两种 key) - `bool` (虽然很少用到,因为它只能表达两种 key)
- `int`, `uint` 以及它们的变体,例如 `u8`、`i32` 等 - `int`, `uint` 以及它们的变体,例如 `u8`、`i32` 等
- `String` 和 `&str` (提示: `HashMap` 的 key 是 `String` 类型时,你其实可以使用 `&str` 配合 `get` 方法进行查询 - `String` 和 `&str` (提示: `HashMap` 的 key 是 `String` 类型时,你其实可以使用 `&str` 配合 `get` 方法进行查询
需要注意的是,`f32` 和 `f64` 并没有实现 `Hash`,原因是 [浮点数精度](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) 的问题会导致它们无法进行相等比较。 需要注意的是,`f32` 和 `f64` 并没有实现 `Hash`,原因是 [浮点数精度](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) 的问题会导致它们无法进行相等比较。
如果一个集合类型的所有字段都实现了 `Eq` 和 `Hash`,那该集合类型会自动实现 `Eq` 和 `Hash`。例如 `Vect<T>` 要实现 `Hash`,那么首先需要 `T` 实现 `Hash`。 如果一个集合类型的所有字段都实现了 `Eq` 和 `Hash`,那该集合类型会自动实现 `Eq` 和 `Hash`。例如 `Vect<T>` 要实现 `Hash`,那么首先需要 `T` 实现 `Hash`。
4. 🌟🌟 4. 🌟🌟
```rust,editable ```rust,editable
// 修复错误 // 修复错误
@ -143,9 +148,11 @@ fn main() {
``` ```
### 容量 ### 容量
关于容量,我们在之前的 [Vector](https://zh.practice.rs/collections/vector.html#容量) 中有详细的介绍,而 `HashMap` 也可以调整容量: 你可以通过 `HashMap::with_capacity(uint)` 使用指定的容量来初始化,或者使用 `HashMap::new()` ,后者会提供一个默认的初始化容量。 关于容量,我们在之前的 [Vector](https://zh.practice.rs/collections/vector.html#容量) 中有详细的介绍,而 `HashMap` 也可以调整容量: 你可以通过 `HashMap::with_capacity(uint)` 使用指定的容量来初始化,或者使用 `HashMap::new()` ,后者会提供一个默认的初始化容量。
#### 示例 #### 示例
```rust,editable ```rust,editable
use std::collections::HashMap; use std::collections::HashMap;
@ -169,10 +176,11 @@ fn main() {
``` ```
### 所有权 ### 所有权
对于实现了 `Copy` 特征的类型,例如 `i32`,那类型的值会被拷贝到 `HashMap` 中。而对于有所有权的类型,例如 `String`,它们的值的所有权将被转移到 `HashMap` 中。 对于实现了 `Copy` 特征的类型,例如 `i32`,那类型的值会被拷贝到 `HashMap` 中。而对于有所有权的类型,例如 `String`,它们的值的所有权将被转移到 `HashMap` 中。
5. 🌟🌟 5. 🌟🌟
```rust,editable ```rust,editable
// 修复错误,尽可能少的去修改代码 // 修复错误,尽可能少的去修改代码
// 不要移除任何代码行! // 不要移除任何代码行!
@ -187,7 +195,7 @@ fn main() {
let mut m2 = HashMap::new(); let mut m2 = HashMap::new();
// 所有权在这里发生了转移 // 所有权在这里发生了转移
m2.insert(v2, v1); m2.insert(v2, v1);
assert_eq!(v2, "hello"); assert_eq!(v2, "hello");
println!("Success!") println!("Success!")
@ -195,6 +203,7 @@ fn main() {
``` ```
### 三方库 Hash 库 ### 三方库 Hash 库
在开头,我们提到过如果现有的 `SipHash 1-3` 的性能无法满足你的需求,那么可以使用社区提供的替代算法。 在开头,我们提到过如果现有的 `SipHash 1-3` 的性能无法满足你的需求,那么可以使用社区提供的替代算法。
例如其中一个社区库的使用方式如下: 例如其中一个社区库的使用方式如下:
@ -211,4 +220,4 @@ hash.insert(42, "the answer");
assert_eq!(hash.get(&42), Some(&"the answer")); assert_eq!(hash.get(&42), Some(&"the answer"));
``` ```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it > You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -35,7 +35,7 @@ fn main() {
```rust,editable ```rust,editable
fn main() { fn main() {
let arr: [i32; 5] = [1, 2, 3, 4, 5]; let arr: [i32; 5] = [1, 2, 3, 4, 5];
// 填空让代码工作起来 // 填空让代码工作起来
let slice: __ = __; let slice: __ = __;
assert_eq!(slice, &[2, 3, 4]); assert_eq!(slice, &[2, 3, 4]);

View File

@ -9,7 +9,7 @@
// 修复错误,不要新增代码行 // 修复错误,不要新增代码行
fn main() { fn main() {
let s: str = "hello, world"; let s: str = "hello, world";
} }
``` ```
@ -20,8 +20,8 @@ fn main() {
// 使用至少两种方法来修复错误 // 使用至少两种方法来修复错误
fn main() { fn main() {
let s: Box<str> = "hello, world".into(); let s: Box<str> = "hello, world".into();
greetings(s) greetings(s)
} }
fn greetings(s: &str) { fn greetings(s: &str) {
@ -37,11 +37,11 @@ fn greetings(s: &str) {
// 填空 // 填空
fn main() { fn main() {
let mut s = __; let mut s = __;
s.push_str("hello, world"); s.push_str("hello, world");
s.push('!'); s.push('!');
assert_eq!(s, "hello, world!"); assert_eq!(s, "hello, world!");
} }
``` ```
@ -50,7 +50,7 @@ fn main() {
// 修复所有错误,并且不要新增代码行 // 修复所有错误,并且不要新增代码行
fn main() { fn main() {
let s = String::from("hello"); let s = String::from("hello");
s.push(','); s.push(',');
s.push(" world"); s.push(" world");
s += "!".to_string(); s += "!".to_string();
@ -64,11 +64,11 @@ fn main() {
// 填空 // 填空
fn main() { fn main() {
let s = String::from("I like dogs"); let s = String::from("I like dogs");
// 以下方法会重新分配一块内存空间,然后将修改后的字符串存在这里 // 以下方法会重新分配一块内存空间,然后将修改后的字符串存在这里
let s1 = s.__("dogs", "cats"); let s1 = s.__("dogs", "cats");
assert_eq!(s1, "I like cats") assert_eq!(s1, "I like cats")
} }
``` ```
@ -98,23 +98,23 @@ fn main() {
// 使用至少两种方法来修复错误 // 使用至少两种方法来修复错误
fn main() { fn main() {
let s = "hello, world"; let s = "hello, world";
greetings(s) greetings(s)
} }
fn greetings(s: String) { fn greetings(s: String) {
println!("{}",s) println!("{}",s)
} }
``` ```
8. 🌟🌟 我们可以使用 `String::from` 或 `to_string` 将 `&str` 转换成 `String` 类型 8. 🌟🌟 我们可以使用 `String::from` 或 `to_string` 将 `&str` 转换成 `String` 类型
```rust,editable ```rust,editable
// 使用两种方法来解决错误,不要新增代码行 // 使用两种方法来解决错误,不要新增代码行
fn main() { fn main() {
let s = "hello, world".to_string(); let s = "hello, world".to_string();
let s1: &str = s; let s1: &str = s;
} }
``` ```
@ -135,7 +135,7 @@ fn main() {
unicode_codepoint, character_name ); unicode_codepoint, character_name );
// 还能使用 \ 来连接多行字符串 // 还能使用 \ 来连接多行字符串
let long_string = "String literals let long_string = "String literals
can span multiple lines. can span multiple lines.
The linebreak and indentation here \ The linebreak and indentation here \
can be escaped too!"; can be escaped too!";
@ -247,10 +247,10 @@ fn main() {
```rust ```rust
use utf8_slice; use utf8_slice;
fn main() { fn main() {
let s = "The 🚀 goes to the 🌑!"; let s = "The 🚀 goes to the 🌑!";
let rocket = utf8_slice::slice(s, 4, 5); let rocket = utf8_slice::slice(s, 4, 5);
// 结果是 "🚀" // 结果是 "🚀"
} }
``` ```

View File

@ -16,8 +16,8 @@ fn main() {
// 修改合适的地方,让代码工作 // 修改合适的地方,让代码工作
fn main() { fn main() {
let t = ("i", "am", "sunface"); let t = ("i", "am", "sunface");
assert_eq!(t.1, "sunface"); assert_eq!(t.1, "sunface");
} }
``` ```
@ -64,11 +64,11 @@ fn main() {
```rust,editable ```rust,editable
fn main() { fn main() {
// 填空,需要稍微计算下 // 填空,需要稍微计算下
let (x, y) = sum_multiply(__); let (x, y) = sum_multiply(__);
assert_eq!(x, 5); assert_eq!(x, 5);
assert_eq!(y, 6); assert_eq!(y, 6);
} }
fn sum_multiply(nums: (i32, i32)) -> (i32, i32) { fn sum_multiply(nums: (i32, i32)) -> (i32, i32) {

View File

@ -100,7 +100,8 @@ fn foo() -> i32 {
fn main() { fn main() {
let pointer = foo as *const (); let pointer = foo as *const ();
let function = unsafe { let function = unsafe {
std::mem::transmute::<*const (), fn() -> i32>(pointer) std::mem::transmute::<*const (), fn() -> i32>(pointer)
};
assert_eq!(function(), 0); assert_eq!(function(), 0);
} }
``` ```

View File

@ -143,4 +143,4 @@ fn main() {
} }
``` ```
> 你可以在[这里](https://github.com/sunface/rust-by-practice)找到答案(在 solutions 路径下) > [答案](https://github.com/sunface/rust-by-practice/blob/master/solutions/variables.md) 在 solutions 下面