加餐|愚昧之巅:你的Rust学习常见问题汇总

293 阅读3分钟

正式开始

所有权问题

Q:想要创建双向链表,该怎么处理?

  1. 标准库中LinkedList,它是一个双向链表的实现
  2. 一个链表实现参考
  3. Weak 相当于一个弱化版本的 Rc,不参与到引用计数的计算中,而 Weak 可以 upgrade 到 Rc 来使用

Q:编译器总告诉我:“use of moved value” 错误,该怎么破?

  1. 这个错误是说你在试图访问一个所有权已经移走的变量
  2. 如果需要多个所有者共享同一份数据,可以使用 Rc / Arc,辅以 Cell / RefCell / Mutex / RwLock
  3. 如果不需要多个所有者共享,那可以考虑实现 Clone 甚至 Copy

生命周期问题

Q:为什么我的函数返回一个引用的时候,编译器总是跟我过不去?

  1. 函数返回引用时,除非是静态引用,那么这个引用一定和带有引用的某个输入参数有关
  2. 输入参数可能是 &self、&mut self 或者 &T / &mut T
  3. 我们要建立正确的输入和返回值之间的关系,这个关系和函数内部的实现无关,只和函数的签名有关
  4. 当你要返回和参数无关的在函数执行过程中创建的或者得到的数据,那么无论它是一个有所有权的数据还是一个引用,你只能返回带所有权的数据。对于引用,这就意味着调用 clone() 或者 to_owned() 来,从引用中得到所有权

数据结构问题

Q:为什么 Rust 字符串这么混乱,有 String、&String、&str 这么多不同的表述?

  1. 任何数据结构 T,都可以有指向它的引用 &T,所以 String 跟 &String 的区别,以及 String 跟 &str 的区别,压根是两个问题

  2. &str 是 String 的切片,也可以是 &str 的切片。它和 &[T] 一样,没有什么特别的,就是一个带着长度的胖指针,指向了一片连续的内存区域

Q:在 Rust 里,我如何声明全局变量呢?

  1. const 和 static,它们都可以用于声明全局变量。但注意,除非使用 unsafe,static 无法作为 mut 使用,因为这意味着它可能在多个线程下被修改,所以不安全

调试工具

Q:Rust 下,一般如何调试应用程序?

  1. 一般会用 tracing 来打日志,一些简单的示例代码会使用 println! / dbg! ,来查看数据结构在某个时刻的状态

如何学习

好用链接

  1. 标准库中LinkedList
  2. Weak
  3. upgrade
  4. 一个链表实现参考
  5. NonNull指针
  6. HashMap的get方法
  7. lazy_static
  8. rust-gdb
  9. rust-lldb
  10. 优化Rust编译的二进制大小

新鲜知识点

  1. 列表Vec<T>,循环缓冲区 VecDequeue<T>

精选问答


use std::str::Chars;

// 错误,为什么?
fn lifetime1() -> &str {
    let name = "Tyr".to_string();
    &name[1..]
}
/*
name为函数内部的临时变量,类型是String,函数返回值为其引用,
但引用的变量name生命周期在函数结束时,会被drop,因此此处引用失效,无值可借;
*/

// 错误,为什么?
fn lifetime2(name: String) -> &str {
    &name[1..]
}
/*
name为具有所有权的参数,类型是String,
在函数被调用时,所有权会move给name,
在函数执行结束时,name会被drop,因此返回值的引用还是无值可借,编译器无法推导出合理的生命周期;
*/

// 正确,为什么?
fn lifetime3(name: &str) -> Chars {
    name.chars()
}
/*
chars()返回的iterator具有和函数参数name相同的生命周期,
name本身又是一个借用,真正具有所有权的变量存活的比函数久,因此这个函数可以编译通过
*/