正式开始
所有权问题
Q:想要创建双向链表,该怎么处理?
- 标准库中LinkedList,它是一个双向链表的实现
- 一个链表实现参考
- Weak 相当于一个弱化版本的 Rc,不参与到引用计数的计算中,而 Weak 可以 upgrade 到 Rc 来使用
Q:编译器总告诉我:“use of moved value” 错误,该怎么破?
- 这个错误是说你在试图访问一个所有权已经移走的变量
- 如果需要多个所有者共享同一份数据,可以使用 Rc / Arc,辅以 Cell / RefCell / Mutex / RwLock
- 如果不需要多个所有者共享,那可以考虑实现 Clone 甚至 Copy
生命周期问题
Q:为什么我的函数返回一个引用的时候,编译器总是跟我过不去?
- 函数返回引用时,除非是静态引用,那么这个引用一定和带有引用的某个输入参数有关
- 输入参数可能是 &self、&mut self 或者 &T / &mut T
- 我们要建立正确的输入和返回值之间的关系,这个关系和函数内部的实现无关,只和函数的签名有关
- 当你要返回和参数无关的在函数执行过程中创建的或者得到的数据,那么无论它是一个有所有权的数据还是一个引用,你只能返回带所有权的数据。对于引用,这就意味着调用 clone() 或者 to_owned() 来,从引用中得到所有权
数据结构问题
Q:为什么 Rust 字符串这么混乱,有 String、&String、&str 这么多不同的表述?
-
任何数据结构 T,都可以有指向它的引用 &T,所以 String 跟 &String 的区别,以及 String 跟 &str 的区别,压根是两个问题
-
&str 是 String 的切片,也可以是 &str 的切片。它和 &[T] 一样,没有什么特别的,就是一个带着长度的胖指针,指向了一片连续的内存区域
Q:在 Rust 里,我如何声明全局变量呢?
- const 和 static,它们都可以用于声明全局变量。但注意,除非使用 unsafe,static 无法作为 mut 使用,因为这意味着它可能在多个线程下被修改,所以不安全:
调试工具
Q:Rust 下,一般如何调试应用程序?
- 一般会用 tracing 来打日志,一些简单的示例代码会使用 println! / dbg! ,来查看数据结构在某个时刻的状态
如何学习
好用链接
- 标准库中LinkedList
- Weak
- upgrade
- 一个链表实现参考
- NonNull指针
- HashMap的get方法
- lazy_static
- rust-gdb
- rust-lldb
- 优化Rust编译的二进制大小
新鲜知识点
- 列表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本身又是一个借用,真正具有所有权的变量存活的比函数久,因此这个函数可以编译通过
*/