面试题答案
一键面试- 设计复杂数据结构
- 假设我们设计一个博客文章管理的数据结构。文章(
Article
)可以包含多个段落(Paragraph
),每个段落又可以包含多个句子(Sentence
)。
struct Sentence { text: String, } struct Paragraph { sentences: Vec<Sentence>, } struct Article { title: String, paragraphs: Vec<Paragraph>, }
- 如果我们想在段落和文章之间建立一种引用关系,比如段落知道它所属的文章,可以使用
Rc
(引用计数)和Weak
(弱引用)。Rc
用于共享所有权,Weak
用于避免循环引用。
use std::rc::Rc, Weak; struct Sentence { text: String, } struct Paragraph { sentences: Vec<Sentence>, article: Weak<Article>, } struct Article { title: String, paragraphs: Vec<Rc<Paragraph>>, }
- 假设我们设计一个博客文章管理的数据结构。文章(
- 所有权模型运用
- 添加元素:
- 当添加一个新的
Paragraph
到Article
时,Article
获得Paragraph
的所有权。由于我们使用Rc
,Paragraph
可以被多个地方引用。
let mut article = Article { title: "My Article".to_string(), paragraphs: Vec::new(), }; let para = Rc::new(Paragraph { sentences: Vec::new(), article: Weak::new(), }); article.paragraphs.push(para.clone()); // 设置段落对文章的弱引用 if let Some(article_ref) = article.paragraphs[0].upgrade() { article_ref.paragraphs[0].article = Rc::downgrade(&article_ref); }
- 当添加一个新的
- 删除元素:
- 当从
Article
中删除一个Paragraph
时,Paragraph
的引用计数会减少。如果引用计数降为0,Paragraph
及其内部的Sentence
会被自动释放。
article.paragraphs.clear(); // 此时所有Paragraph及其内部的Sentence都被释放,因为没有其他强引用
- 当从
- 添加元素:
- 兼顾性能与代码可读性
- 性能:
- 使用
Rc
和Weak
在大多数情况下性能开销较小,因为引用计数的操作(增加和减少)是非常轻量级的。但要注意避免过多的引用计数操作导致的性能问题,例如在循环中频繁创建和销毁Rc
对象。
- 使用
- 代码可读性:
- 给结构体和方法命名有意义的名称,使代码逻辑清晰。例如,我们可以为
Article
和Paragraph
添加方法来管理元素,而不是直接操作内部的Vec
。
impl Article { fn add_paragraph(&mut self, para: Rc<Paragraph>) { self.paragraphs.push(para.clone()); if let Some(article_ref) = self.paragraphs.last().and_then(|p| p.upgrade()) { article_ref.paragraphs.last_mut().unwrap().article = Rc::downgrade(&article_ref); } } }
- 这样的方法调用使得代码更易读,并且封装了内部实现细节,比如设置段落对文章的弱引用逻辑。同时,使用注释来解释复杂的所有权和引用关系,如上面代码中的注释说明设置弱引用的目的。
- 给结构体和方法命名有意义的名称,使代码逻辑清晰。例如,我们可以为
- 性能: