From b276e6db4136c78050ae2b59398dffbe2bcba9a5 Mon Sep 17 00:00:00 2001 From: sunface Date: Wed, 9 Mar 2022 16:34:49 +0800 Subject: [PATCH] add type-conversions/as.md --- solutions/type-conversions/as.md | 88 ++++++++++++++++++++++++++ src/SUMMARY.md | 3 +- src/collections/hashmap.md | 2 + src/type-conversion.md | 1 - src/type-conversions/as.md | 103 +++++++++++++++++++++++++++++++ src/type-conversions/intro.md | 2 + zh-CN/src/collections/String.md | 2 +- zh-CN/src/collections/hashmap.md | 6 +- 8 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 solutions/type-conversions/as.md delete mode 100644 src/type-conversion.md create mode 100644 src/type-conversions/as.md create mode 100644 src/type-conversions/intro.md diff --git a/solutions/type-conversions/as.md b/solutions/type-conversions/as.md new file mode 100644 index 0000000..1a36f7c --- /dev/null +++ b/solutions/type-conversions/as.md @@ -0,0 +1,88 @@ +1. +```rust +fn main() { + let decimal = 97.123_f32; + + let integer: u8 = decimal as u8; + + let c1: char = decimal as u8 as char; + let c2 = integer as char; + + assert_eq!(integer, 'b' as u8 - 1); +} +``` + +2. +```rust +// Suppress all warnings from casts which overflow. +#![allow(overflowing_literals)] + +fn main() { + assert_eq!(u8::MAX, 255); + let v = 1000 as u8; +} +``` + +3. +```rust +fn main() { + assert_eq!(1000 as u16, 1000); + + assert_eq!(1000 as u8, 232); + + // For positive numbers, this is the same as the modulus + println!("1000 mod 256 is : {}", 1000 % 256); + + assert_eq!(-1_i8 as u8, 255); + + // Since Rust 1.45, the `as` keyword performs a *saturating cast* + // when casting from float to int. If the floating point value exceeds + // the upper bound or is less than the lower bound, the returned value + // will be equal to the bound crossed. + assert_eq!(300.1_f32 as u8, 255); + assert_eq!(-100.1_f32 as u8, 0); + + + // This behavior incurs a small runtime cost and can be avoided + // with unsafe methods, however the results might overflow and + // return **unsound values**. Use these methods wisely: + unsafe { + // 300.0 is 44 + println!("300.0 is {}", 300.0_f32.to_int_unchecked::()); + // -100.0 as u8 is 156 + println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::()); + // nan as u8 is 0 + println!("nan as u8 is {}", f32::NAN.to_int_unchecked::()); + } +} +``` + +4. +```rust +fn main() { + let mut values: [i32; 2] = [1, 2]; + let p1: *mut i32 = values.as_mut_ptr(); + let first_address = p1 as usize; + let second_address = first_address + 4; // 4 == std::mem::size_of::() + let p2 = second_address as *mut i32; + unsafe { + *p2 += 1; + } + assert_eq!(values[1], 3); + + println!("Success!") +} +``` + +5. +```rust +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), 13) + } +} +``` \ No newline at end of file diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 85b03e3..925e68f 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -32,7 +32,8 @@ - [String](collections/string.md) - [Vector](collections/vector.md) - [HashMap](collections/hashmap.md) -- [Type Conversion todo](type-conversion.md) +- [Type Conversion](type-conversions/intro.md) + - [as](type-conversions/as.md) - [Result and panic todo](result-panic/intro.md) - [panic!](result-panic/panic.md) - [result and ?](result-panic/result.md) diff --git a/src/collections/hashmap.md b/src/collections/hashmap.md index b5619b3..a54ff99 100644 --- a/src/collections/hashmap.md +++ b/src/collections/hashmap.md @@ -199,6 +199,8 @@ fn main() { m2.insert(v2, v1); assert_eq!(v2, "hello"); + + println!("Success!") } ``` diff --git a/src/type-conversion.md b/src/type-conversion.md deleted file mode 100644 index 7b930e5..0000000 --- a/src/type-conversion.md +++ /dev/null @@ -1 +0,0 @@ -# Type Conversion diff --git a/src/type-conversions/as.md b/src/type-conversions/as.md new file mode 100644 index 0000000..2eae718 --- /dev/null +++ b/src/type-conversions/as.md @@ -0,0 +1,103 @@ +# Type Conversions +Rust provides no implicit type conversion(coercion) between primitive types. But explicit type conversions can be performed using the `as` keyword. + +1. 🌟 +```rust,editable +// FIX the errors and FILL in the blank +// DON'T remove any code +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. 🌟🌟 By default, overflow will cause compile errors, but we can add an global annotation to suppress these errors. +```rust,editable +fn main() { + assert_eq!(u8::MAX, 255); + // the max of `u8` is 255 as shown above. + // so the below code will cause an overflow error: literal out of range for `u8`. + // PLEASE looking for clues within compile errors to FIX it. + // DON'T modify any code in main. + let v = 1000 as u8; + + println!("Success!") +} +``` + +3. 🌟🌟 when casting any value to an unsigned type `T`, `T::MAX + 1` is added or subtracted until the value fits into the new type. +```rust,editable +fn main() { + assert_eq!(1000 as u16, __); + + assert_eq!(1000 as u8, __); + + // For positive numbers, this is the same as the modulus + println!("1000 mod 256 is : {}", 1000 % 256); + + assert_eq!(-1_i8 as u8, __); + + // Since Rust 1.45, the `as` keyword performs a *saturating cast* + // when casting from float to int. If the floating point value exceeds + // the upper bound or is less than the lower bound, the returned value + // will be equal to the bound crossed. + assert_eq!(300.1_f32 as u8, __); + assert_eq!(-100.1_f32 as u8, __); + + + // This behavior incurs a small runtime cost and can be avoided + // with unsafe methods, however the results might overflow and + // return **unsound values**. Use these methods wisely: + unsafe { + // 300.0 is 44 + println!("300.0 is {}", 300.0_f32.to_int_unchecked::()); + // -100.0 as u8 is 156 + println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::()); + // nan as u8 is 0 + println!("nan as u8 is {}", f32::NAN.to_int_unchecked::()); + } +} +``` + +4. 🌟🌟🌟 Raw pointer can be converted to memory address (integer) and vice versa +```rust,editable + +// FILL in the blanks +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::() + let p2: *mut i32 = second_address __; // p2 points to the 2nd element in values + unsafe { + // add one to the second element + __ + } + + assert_eq!(values[1], 3); + + println!("Success!") +} +``` + + +5. 🌟🌟🌟 +```rust,editable +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), __) + } +} +``` diff --git a/src/type-conversions/intro.md b/src/type-conversions/intro.md new file mode 100644 index 0000000..b2f15f9 --- /dev/null +++ b/src/type-conversions/intro.md @@ -0,0 +1,2 @@ +# Type conversions +There are several ways we can use to perform type conversions, such as `as`, `From/Intro`, `TryFrom/TryInto`, `transmute` etc. diff --git a/zh-CN/src/collections/String.md b/zh-CN/src/collections/String.md index f75d5ad..3b13e9b 100644 --- a/zh-CN/src/collections/String.md +++ b/zh-CN/src/collections/String.md @@ -150,7 +150,7 @@ fn main() { 存储在栈上的智能指针结构体由三部分组成:一个指针只指向堆上的字节数组,已使用的长度以及已分配的容量 capacity (已使用的长度小于等于已分配的容量,当容量不够时,会重新分配内存空间)。 -1. 🌟🌟 如果 String 的当前容量足够,那么添加字符将不会导致新的内存分配 +6. 🌟🌟 如果 String 的当前容量足够,那么添加字符将不会导致新的内存分配 ```rust,editable // 修改下面的代码以打印如下内容: diff --git a/zh-CN/src/collections/hashmap.md b/zh-CN/src/collections/hashmap.md index c6aa879..c3919c2 100644 --- a/zh-CN/src/collections/hashmap.md +++ b/zh-CN/src/collections/hashmap.md @@ -105,7 +105,7 @@ fn random_stat_buff() -> u8 { 如果一个集合类型的所有字段都实现了 `Eq` 和 `Hash`,那该集合类型会自动实现 `Eq` 和 `Hash`。例如 `Vect` 要实现 `Hash`,那么首先需要 `T` 实现 `Hash`。 -1. 🌟🌟 +4. 🌟🌟 ```rust,editable // 修复错误 @@ -171,7 +171,7 @@ fn main() { 对于实现了 `Copy` 特征的类型,例如 `i32`,那类型的值会被拷贝到 `HashMap` 中。而对于有所有权的类型,例如 `String`,它们的值的所有权将被转移到 `HashMap` 中。 -1. 🌟🌟 +5. 🌟🌟 ```rust,editable // 修复错误,尽可能少的去修改代码 // 不要移除任何代码行! @@ -188,6 +188,8 @@ fn main() { m2.insert(v2, v1); assert_eq!(v2, "hello"); + + println!("Success!") } ```