对于实现了 Copy 特征的类型,例如 i32 ,那类型的值会被拷贝到 HashMap 中。而对于有所有权的类

型,例如 String ,它们的值的所有权将被转移到 HashMap 中。

5. 🌟🌟

// 修 复 错 误 , 尽 可 能 少 的 去 修 改 代 码

// 不 要 移 除 任 何 代 码 行 !

use std::collections::HashMap;

fn main() {

let v1 = 10;

let mut m1 = HashMap::new();

m1.insert(v1, v1);

println!("v1 is still usable after inserting to hashmap : {}", v1);

let v2 = "hello".to_string();

let mut m2 = HashMap::new();

// 所 有 权 在 这 里 发 生 了 转 移

m2.insert(v2, v1);

assert_eq!(v2, "hello");

println!("Success!")

}

三方库 Hash 库

在开头,我们提到过如果现有的 SipHash 1-3 的性能无法满足你的需求,那么可以使用社区提供的替代算

法。

例如其中一个社区库的使用方式如下:

use std::hash::BuildHasherDefault;

use std::collections::HashMap;

// 引入第三方的哈希函数

use twox_hash::XxHash64;

let mut hash: HashMap<_, _, BuildHasherDefault<XxHash64>> = Default::default();

hash.insert(42, "the answer");

assert_eq!(hash.get(&42), Some(&"the answer"));

Type conversions

There are several ways we can use to perform type conversions, such as as , From/Intro ,

TryFrom/TryInto , transmute etc.

使用 as 进行类型转换

Rust 并没有为基本类型提供隐式的类型转换( coercion ),但是我们可以通过 as 来进行显式地转换。

1. 🌟

// 修 复 错 误 , 填 空

// 不 要 移 除 任 何 代 码

fn main() {

let decimal = 97.123_f32;

let integer: __ = decimal as u8;

let c1: char = decimal as char;

let c2 = integer as char;

assert_eq!(integer, 'b' as u8);

println!("Success!")

}

2. 🌟🌟 默认情况下, 数值溢出会导致编译错误,但是我们可以通过添加一行全局注解的方式来避免编

译错误(溢出还是会发生)

fn main() {

assert_eq!(u8::MAX, 255);

// 如 上 所 示 ,u8 类 型 允 许 的 最 大 值 是 255.

// 因 此 以 下 代 码 会 报 溢 出 的 错 误 : literal out of range for `u8`.

// **请 仔 细 查 看 相 应 的 编 译 错 误 , 从 中 寻 找 到 解 决 的 办 法**

// **不 要 修 改 main 中 的 任 何 代 码**

let v = 1000 as u8;

println!("Success!")

}

3. 🌟🌟 当将任何数值转换成无符号整型 T 时,如果当前的数值不在新类型的范围内,我们可以对当

前数值进行加值或减值操作( 增加或减少 T::MAX + 1 ),直到最新的值在新类型的范围内,假设我们

要将 300 转成 u8 类型,由于 u8 最大值是 255,因此 300 不在新类型的范围内并且大于新类型的

最大值,因此我们需要减去 T::MAX + 1 ,也就是 300 - 256 = 44 。

fn main() {

assert_eq!(1000 as u16, __);

assert_eq!(1000 as u8, __);

// 事 实 上 , 之 前 说 的 规 则 对 于 正 整 数 而 言 , 就 是 如 下 的 取 模

println!("1000 mod 256 is : {}", 1000 % 256);

assert_eq!(-1_i8 as u8, __);

// 从 Rust 1.45 开 始 , 当 浮 点 数 超 出 目 标 整 数 的 范 围 时 , 转 化 会 直 接 取 正 整 数 取 值 范 围 的 最 大 或

assert_eq!(300.1_f32 as u8, __);

assert_eq!(-100.1_f32 as u8, __);

// 上 面 的 浮 点 数 转 换 有 一 点 性 能 损 耗 , 如 果 大 家 对 于 某 段 代 码 有 极 致 的 性 能 要 求 ,

// 可 以 考 虑 下 面 的 方 法 , 但 是 这 些 方 法 的 结 果 可 能 会 溢 出 并 且 返 回 一 些 无 意 义 的 值

// 总 之 , 请 小 心 使 用

unsafe {

// 300.0 is 44

println!("300.0 is {}", 300.0_f32.to_int_unchecked::<u8>());

// -100.0 as u8 is 156

println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::<u8>());

// nan as u8 is 0

println!("nan as u8 is {}", f32::NAN.to_int_unchecked::<u8>());

}

}

4. 🌟🌟🌟 裸指针可以和代表内存地址的整数互相转换

// 填 空

fn main() {

let mut values: [i32; 2] = [1, 2];

let p1: *mut i32 = values.as_mut_ptr();

let first_address: usize = p1 __;

let second_address = first_address + 4; // 4 == std::mem::size_of::<i32>()

let p2: *mut i32 = second_address __; // p2 指 向 values 数 组 中 的 第 二 个 元 素

unsafe {

// 将 第 二 个 元 素 加 1

__

}

assert_eq!(values[1], 3);

println!("Success!")

}

5. 🌟🌟🌟

fn main() {

let arr :[u64; 13] = [0; 13];

assert_eq!(std::mem::size_of_val(&arr), 8 * 13);

let a: *const [u64] = &arr;

let b = a as *const [u8];

unsafe {

assert_eq!(std::mem::size_of_val(&*b), __)

}

}