其它转换

将任何类型转换成 String

只要为一个类型实现了 ToString,就可以将任何类型转换成 String。事实上,这种方式并不是最好的,大家还记得 fmt::Display 特征吗?它可以控制一个类型如何打印,在实现它的时候还会自动实现 ToString。

  1. 🌟🌟
1. use std::fmt;

3. struct Point {
4. x: i32,
5. y: i32,
6. }

8. impl fmt::Display for Point {
9. // 实现 fmt 方法
10. }

12. fn main() {
13. let origin = Point { x: 0, y: 0 };
14. // 填空
15. assert_eq!(origin.__, "The point is (0, 0)");
16. assert_eq!(format!(__), "The point is (0, 0)");

18. println!("Success!")
19. }

解析 String

  1. 🌟🌟🌟 使用 parse 方法可以将一个 String 转换成 i32 数字,这是因为在标准库中为 i32 类型实现了 FromStr: : impl FromStr for i32
1. // 为了使用 `from_str` 方法, 你需要引入该特征到当前作用域中
2. use std::str::FromStr;
3. fn main() {
4. let parsed: i32 = "5".__.unwrap();
5. let turbo_parsed = "10".__.unwrap();
6. let from_str = __.unwrap();
7. let sum = parsed + turbo_parsed + from_str;
8. assert_eq!(sum, 35);

10. println!("Success!")
11. }
  1. 🌟🌟 还可以为自定义类型实现 FromStr 特征
1. use std::str::FromStr;
2. use std::num::ParseIntError;

4. #[derive(Debug, PartialEq)]
5. struct Point {
6. x: i32,
7. y: i32
8. }

10. impl FromStr for Point {
11. type Err = ParseIntError;

13. fn from_str(s: &str) -> Result<Self, Self::Err> {
14. let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
15. .split(',')
16. .map(|x| x.trim())
17. .collect();

19. let x_fromstr = coords[0].parse::<i32>()?;
20. let y_fromstr = coords[1].parse::<i32>()?;

22. Ok(Point { x: x_fromstr, y: y_fromstr })
23. }
24. }
25. fn main() {
26. // 使用两种方式填空
27. // 不要修改其它地方的代码
28. let p = __;
29. assert_eq!(p.unwrap(), Point{ x: 3, y: 4} );

31. println!("Success!")
32. }

Deref 特征

Deref 特征在智能指针 - Deref章节中有更加详细的介绍。

transmute

std::mem::transmute 是一个 unsafe 函数,可以把一个类型按位解释为另一个类型,其中这两个类型必须有同样的位数( bits )。

transmute 相当于将一个类型按位移动到另一个类型,它会将源值的所有位拷贝到目标值中,然后遗忘源值。该函数跟 C 语言中的 memcpy 函数类似。

正因为此,transmute 非常非常不安全! 调用者必须要自己保证代码的安全性,当然这也是 unsafe 的目的。

示例

  1. transmute 可以将一个指针转换成一个函数指针,该转换并不具备可移植性,原因是在不同机器上,函数指针和数据指针可能有不同的位数( size )。
1. fn foo() -> i32 {
2. 0
3. }

5. fn main() {
6. let pointer = foo as *const ();
7. let function = unsafe {
8. std::mem::transmute::<*const (), fn() -> i32>(pointer)
9. };
10. assert_eq!(function(), 0);
11. }
  1. transmute 还可以扩展或缩短一个不变量的生命周期,将 Unsafe Rust 的不安全性体现的淋漓尽致!
1. struct R<'a>(&'a i32);
2. unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
3. std::mem::transmute::<R<'b>, R<'static>>(r)
4. }

6. unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
7. -> &'b mut R<'c> {
8. std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
9. }
  1. 事实上我们还可以使用一些安全的方法来替代 transmute.
1. fn main() {
2. /*Turning raw bytes(&[u8]) to u32, f64, etc.: */
3. let raw_bytes = [0x78, 0x56, 0x34, 0x12];

5. let num = unsafe { std::mem::transmute::<[u8; 4], u32>(raw_bytes) };

7. // use `u32::from_ne_bytes` instead
8. let num = u32::from_ne_bytes(raw_bytes);
9. // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness
10. let num = u32::from_le_bytes(raw_bytes);
11. assert_eq!(num, 0x12345678);
12. let num = u32::from_be_bytes(raw_bytes);
13. assert_eq!(num, 0x78563412);

15. /*Turning a pointer into a usize: */
16. let ptr = &0;
17. let ptr_num_transmute = unsafe { std::mem::transmute::<&i32, usize>(ptr) };

19. // Use an `as` cast instead
20. let ptr_num_cast = ptr as *const i32 as usize;

22. /*Turning an &mut T into an &mut U: */
23. let ptr = &mut 0;
24. let val_transmuted = unsafe { std::mem::transmute::<&mut i32, &mut u32>(ptr) };

26. // Now, put together `as` and reborrowing - note the chaining of `as`
27. // `as` is not transitive
28. let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };

30. /*Turning an &str into a &[u8]: */
31. // this is not a good way to do this.
32. let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
33. assert_eq!(slice, &[82, 117, 115, 116]);

35. // You could use `str::as_bytes`
36. let slice = "Rust".as_bytes();
37. assert_eq!(slice, &[82, 117, 115, 116]);

39. // Or, just use a byte string, if you have control over the string
40. // literal
41. assert_eq!(b"Rust", &[82, 117, 115, 116]);
42. }

你可以在这里找到答案(在 solutions 路径下)