加餐|愚昧之巅:你的Rust学习常见问题汇总
该思维导图由 AI 生成,仅供参考
所有权问题
- 深入了解
- 翻译
- 解释
- 总结
Rust学习中常见问题汇总 本文深入探讨了Rust学习中常见问题,包括所有权、生命周期、数据结构等多个方面。针对每个问题提供了解决方法和建议,强调了在生产环境中使用模式匹配和错误处理的重要性,以及避免使用unsafe代码的建议。文章还介绍了调试工具的使用方法,解释了Rust编译出的二进制大小和运行速度的问题。此外,还提到了Rust语言不断发展的特性,以及对最新版本的建议。通过解答常见问题,帮助读者更好地理解和应用Rust语言的特性。
《陈天 · Rust 编程第一课》,新⼈⾸单¥68
全部留言(27)
- 最新
- 精选
- 秋声赋置顶我看到用了很多的宏,这个有没有详细的说明呢?
编辑回复: 06那篇有简单讲到宏,不过因为宏是高级内容在课程里目前没有详细讲解,你可以自己找资料学习。之后老师有空会补充一篇关于宏的内容,也欢迎期待~
2022-01-112 - lisiur第一个,没有标注生命周期,但即使标注也不对,因为返回值引用了本地已经 drop 的 String,会造成悬垂指针问题; 第二个,和第一个类似,因为参数是具有所有权的 String,该 String 会在函数执行完后被 drop,返回值不能引用该 String; 第三个,因为 Chars 的完整定义是 Chars<'a>,根据生命周期标注规则,Chars 内部的引用的生命周期和参数 name 一致,所以不会产生问题。
作者回复: 非常棒!
2021-09-1745 - 乌龙猹陈老师,啥时候再出一门 Elixir 编程的第一课啊
作者回复: :) 做这一门课我就感觉已经竭尽全力了,做完估计要休半年才能缓过来
2021-09-17721 - Arthurlifetime1: name为函数内部的临时变量,类型是String,函数返回值为其引用,但引用的变量name生命周期在函数结束时,会被drop,因此此处引用失效,无值可借; lifetime2: name为具有所有权的参数,类型是String,在函数被调用时,所有权会move给name,在函数执行结束时,name会被drop,因此返回值的引用还是无值可借,编译器无法推导出合理的生命周期; lifetime3: chars()返回的iterator具有和函数参数name相同的生命周期,name本身又是一个借用,真正具有所有权的变量存活的比函数久,因此这个函数可以编译通过 参考材料: 编译器报错信息 ```plain | 12 | fn lifetime1() -> &str { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from --> src/main.rs:18:31 | 18 | fn lifetime2(name: String) -> &str { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments ``` 标准库具体实现 ```rust // Returns an iterator over the chars of a string slice. pub fn chars(&self) -> Chars<'_> // Converts the given value to a String. fn to_string(&self) -> String ```
作者回复: 非常好,目前最棒的答案!
2021-09-1710 - gnulifetime1: 返回的引用是在 lifetime1 里被分配,lifetime1 结束后引用就被回收,所以错误。 改为转成 string 后返回。 ``` fn lifetime1() -> String { let name = "Tyr".to_string(); name[1..].to_string() } ``` lifetime2: 函数参数是 String,编译器无法通过参数确定返回值 &str 的生命周期。 修改为 ``` fn lifetime2(name: &String) -> &str { &name[1..] } ``` lifetime3: 返回 Chars 类型的生命周期与参数 name 关联,所以正确。
作者回复: 非常棒!修改得也很棒!
2021-09-1710 - 彭亚伦关于String 和 &str相关的各种问题, 我的经验, 一个核心原因是因为 String 实现了Deref<Target = str>, String和&str是通过这个Deref Trait建立了互换的关系; 这样做带来了很多便利, 同时也有个side effect, 就是当参数要求是 &str 时, 实参可能是&str也可能是&String, 而两者的生命周期明显是不一样的, 于是就产生了各种看似比较难以琢磨的问题.
作者回复: &str / &String 生命周期为什么不一样?生命周期和类型无关,和数据有关。我猜你说 &str 和 &String 声明周期不一样,是因为我们会使用 string literal,比如: let s1 = "hello"; let s2 = "hello".to_stirng(); 这两者生命周期不一样是因为 "hello" 本身是 &'static(编译时放在 RODATA section 中),而 s2 复制了一份 "hello" 放在堆上。
2021-10-265 - 记事本老师,关于智能指针一些问题: 数据放在堆上,返回指针给栈上的结构体 智能指针有个特点,*解耦到原型,&*就是获取数据的引用,单&栈上结构体的地址 *因为会解耦出原型,所以原数据是否实现copy trait,否则会move,智能指针就没有所有权了
作者回复: 是的,所以 * 不能直接使用在诸如 String / Vec 这样数据结构的引用上。当你尝试这样做,编译器会报错:数据被 borrow,但又被 move,且没有实现 copy,所以错误。 ```rust fn main() { let s = "hello".to_string(); let r1 = &s; let s1 = *r1; println!("{:?}", s1); } ``` 所以这里会编译出错,而不是移动所有权。你不能一边借用,一边移动所有权。
2021-09-1725 - Kerry例子一: 1. &str生命周期不明确 2. 返回了局部函数拥有所有权的引用,也是生命周期问题 可改为: fn lifetime1() -> &'static str { let name = "Tyr"; &name[1..] } 例子二: 函数参数不是引用类型,而且String没有实现Copy Trait,传参的时候会把形参的所有权给到实参,这时候跟例子一是一样的。解决办法是把形参定义为引用类型,如&str(&String也不是不行): fn lifetime2(name: &str) -> &str { &name[1..] } 注意这里例子二不用指定返回值的生命周期,因为编译器可以从参数列表自动推断。 例子三: Chars是字符串切片迭代器,生命周期与&str是一致的,这一点可以从签名中看出: // std::str::chars pub fn chars(&self) -> Chars<'_> // std::str::Chars pub struct Chars<'a> { pub(super) iter: slice::Iter<'a, u8>, }
作者回复: 👍 非常好。要注意的是例子 1 的改法并不是通用的,它只适合少数可以 &'static 的情况。
2021-09-183 - 罗杰比较简单的问题,第一个 name 在函数里面创建的 String,函数返回时就释放掉了,这是最直白的悬垂引用。第二个 name 是从调用者 move 过来的 String,进入该函数,所有权就归函数了,返回时 name 也将被释放。第三个 name 不用加生命周期标注可以正常工作,参数是引用,返回的数据与该参数的生命周期相同,没有问题,可以编译通过。
作者回复: 非常棒!
2021-09-173 - 亚伦碎语对&str 和 &String的区别,更新一点: String可以动态的调整内存大小。 str不能resize. &str直接是指到了String存储的引用,&String是对于String内存对象的引用。 参考: https://users.rust-lang.org/t/whats-the-difference-between-string-and-str/10177/8
作者回复: 嗯。其实不必这么记。还是要抓住 String 和 str 的实质。一个拥有所有权(自然也可以 put_str),一个没有所有权,只是切片(自然不能 resize 别人的东西)。
2021-09-232