当前位置: 首页 > news >正文

Rust面试题及详细答案120道(58-65)-- 集合类型

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 58. 简述Rust标准库中的主要集合类型(`Vec`、`String`、`HashMap`等)
      • 59. `Vec<T>`的基本操作(创建、添加、删除、访问元素),如何避免越界访问?
        • 基本操作示例:
        • 避免越界访问的方法:
      • 60. `String`与`&str`的关系,`String`的内部结构是什么(提示:`Vec<u8>`)?
        • `String`与`&str`的关系:
        • `String`的内部结构:
      • 61. 如何处理UTF-8编码的字符串?为什么`String`不能直接通过索引访问字符?
        • 处理UTF-8编码的字符串:
        • 为什么`String`不能直接通过索引访问字符?
      • 62. `HashMap<K, V>`的使用场景,如何插入、查询、删除键值对?
        • `HashMap<K, V>`的使用场景:
        • 基本操作示例:
        • 其他常用操作:
      • 63. `BTreeMap`与`HashMap`的区别,何时选择`BTreeMap`?
        • `BTreeMap`与`HashMap`的区别:
        • 何时选择`BTreeMap`?
      • 64. `HashSet`和`BTreeSet`的特点,如何判断元素是否存在?
        • `HashSet<T>`的特点:
        • `BTreeSet<T>`的特点:
        • 判断元素是否存在的方法:
      • 65. 什么是“切片(Slice)”?`&[T]`和`&str`的关系是什么?
        • 切片(Slice)的定义:
        • 切片的特点:
        • `&[T]`和`&str`的关系:
  • 二、120道Rust面试题目录列表

一、本文面试题目录

58. 简述Rust标准库中的主要集合类型(VecStringHashMap等)

Rust标准库提供了多种集合类型,用于存储和管理数据集合,它们都在堆上分配内存,且具有不同的特性和适用场景。主要集合类型包括:

  • Vec<T>(动态数组)

    • 原理:连续存储相同类型T的元素,支持动态扩容,内部基于Vec<u8>实现。
    • 特点:随机访问效率高(O(1)),适合存储有序、可重复的元素。
  • String(字符串)

    • 原理:UTF-8编码的可变字符串,内部本质是Vec<u8>,但保证数据符合UTF-8标准。
    • 特点:支持字符串拼接、修改,适合处理文本数据。
  • HashMap<K, V>(哈希表)

    • 原理:基于哈希函数存储键值对(K为键,V为值),通过键快速查找值。
    • 特点:插入和查询效率高(平均O(1)),但元素无序,K需实现HashEq trait。
  • BTreeMap<K, V>(有序映射)

    • 原理:基于B树实现的键值对集合,元素按键的顺序排序。
    • 特点:支持范围查询,插入和查询效率为O(log n),K需实现Ord trait。
  • HashSet<T>(哈希集合)

    • 原理:基于HashMap实现,仅存储键(值为单元类型()),确保元素唯一。
    • 特点:判断元素是否存在效率高(平均O(1)),T需实现HashEq trait。
  • BTreeSet<T>(有序集合)

    • 原理:基于BTreeMap实现,元素唯一且按顺序存储。
    • 特点:支持范围查询和排序,T需实现Ord trait。
  • LinkedList<T>(双向链表)

    • 原理:节点通过指针连接的双向链表,不连续存储。
    • 特点:插入和删除首尾元素效率高(O(1)),但随机访问效率低(O(n)),一般不推荐优先使用。

59. Vec<T>的基本操作(创建、添加、删除、访问元素),如何避免越界访问?

Vec<T>是Rust中最常用的动态数组类型,支持多种操作,同时需注意避免越界访问以保证安全性。

基本操作示例:
fn main() {// 1. 创建Veclet mut v1: Vec<i32> = Vec::new(); // 空Veclet v2 = vec![1, 2, 3]; // 使用vec!宏初始化let v3 = (0..5).collect::<Vec<i32>>(); // 从迭代器收集// 2. 添加元素(push/apppend)v1.push(4);v1.push(5);let mut v4 = vec![6, 7];v1.append(&mut v4); // 合并v4到v1(v4会被清空)println!("v1: {:?}", v1); // [4, 5, 6, 7]// 3. 访问元素let third = &v2[2]; // 索引访问(越界会panic)println!("v2[2]: {}", third); // 3let opt = v2.get(1); // get方法(返回Option<&T>,越界返回None)if let Some(val) = opt {println!("v2[1]: {}", val); // 2}// 4. 删除元素let last = v1.pop(); // 移除最后一个元素(返回Option<T>)println!("pop: {:?}", last); // Some(7)v1.remove(0); // 移除索引0的元素(返回被移除的值)println!("v1 after remove: {:?}", v1); // [5, 6]
}
避免越界访问的方法:
  1. 使用get方法:返回Option<&T>,越界时返回None,可通过if letmatch安全处理。
  2. 检查长度:通过v.len()判断索引是否在有效范围内(0 <= index < v.len())。
  3. 迭代器访问:使用for item in &v遍历元素,无需手动管理索引。
  4. 模式匹配:结合Vecis_empty方法和范围判断,避免访问空数组。

60. String&str的关系,String的内部结构是什么(提示:Vec<u8>)?

String&str的关系:
  • String:是一个可变的、拥有所有权的UTF-8字符串,数据存储在堆上,支持修改(如拼接、插入等)。
  • &str:是一个不可变的字符串切片&[u8]的特化),指向String或静态字符串(&'static str)中的一段连续UTF-8数据,不拥有所有权。
  • 关系:String可以通过&s(或s.as_str())转换为&str,而&str可以通过to_string()String::from()转换为String(会复制数据)。
String的内部结构:

String本质上是对Vec<u8>的封装,其内部结构包含三部分(与Vec一致):

  • 指针:指向堆上存储的UTF-8字节数据。
  • 长度:当前字符串的字节数(len()方法返回)。
  • 容量:堆上分配的总字节数(capacity()方法返回,大于等于长度)。

示例:

fn main() {let s = String::from("hello");// String -> &strlet slice: &str = &s;println!("slice: {}", slice); // hello// &str -> Stringlet s2 = slice.to_string();println!("s2: {}", s2); // hello// 查看String的内部字节(UTF-8编码)let bytes = s.as_bytes(); // &[u8]println!("bytes: {:?}", bytes); // [104, 101, 108, 108, 111](对应"hello"的ASCII码)
}

61. 如何处理UTF-8编码的字符串?为什么String不能直接通过索引访问字符?

处理UTF-8编码的字符串:

UTF-8是一种可变长度的Unicode编码(1-4字节表示一个字符),Rust的String&str均采用UTF-8编码。常见处理方式包括:

  1. 迭代字符:使用chars()方法获取字符迭代器(每个元素是char类型)。
  2. 按字节处理:使用as_bytes()获取字节切片(&[u8]),适合处理原始字节。
  3. 获取子串:使用get()split_at()方法,需确保分割点在UTF-8字符边界上。

示例:

fn main() {let s = String::from("你好,world");// 迭代字符(char)for c in s.chars() {print!("{} ", c); // 你 好 , w o r l d }println!();// 按字节处理(注意:中文字符占3字节)let bytes = s.as_bytes();println!("bytes: {:?}", bytes); // [228, 189, 160, 229, 165, 189, ...]// 安全获取子串(从索引0到6,对应"你好")if let Some(sub) = s.get(0..6) {println!("sub: {}", sub); // 你好}
}
为什么String不能直接通过索引访问字符?
  • UTF-8的可变长度特性:一个char可能占1-4字节(如英文字母1字节,中文3字节),索引访问的是字节位置,而非字符位置,可能导致获取到不完整的字符(如半个中文字符)。
  • 安全性设计:Rust为避免无效的UTF-8数据访问,禁止直接通过索引访问String的字符,强制使用chars()get()等安全方法。

62. HashMap<K, V>的使用场景,如何插入、查询、删除键值对?

HashMap<K, V>的使用场景:
  • 需通过唯一键快速查询值(如字典、缓存、用户ID与信息映射)。
  • 元素无序且对排序无要求。
  • 插入和查询操作频繁,且希望平均时间复杂度为O(1)。
基本操作示例:
use std::collections::HashMap;fn main() {// 创建HashMaplet mut map: HashMap<&str, i32> = HashMap::new();// 1. 插入键值对(insert返回旧值的Option)map.insert("one", 1);let old_val = map.insert("one", 100); // 覆盖旧值"one"println!("old_val: {:?}", old_val); // Some(1)// 2. 查询值(get返回Option<&V>)let val = map.get("one");if let Some(v) = val {println!("one: {}", v); // 100}// 3. 检查键是否存在if map.contains_key("two") {println!("two exists");} else {println!("two not exists"); // 执行此分支}// 4. 删除键值对(remove返回被删除值的Option)let removed = map.remove("one");println!("removed: {:?}", removed); // Some(100)println!("map after remove: {:?}", map); // {}
}
其他常用操作:
  • 遍历for (k, v) in &map 遍历键值对。
  • 更新值entry API(如map.entry("key").or_insert(0),不存在则插入默认值)。

63. BTreeMapHashMap的区别,何时选择BTreeMap

BTreeMapHashMap的区别:
特性HashMap<K, V>BTreeMap<K, V>
内部实现哈希表B树(有序数据结构)
元素顺序无序按键的Ord trait排序
插入/查询复杂度平均O(1),最坏O(n)O(log n)
键的约束K: Hash + EqK: Ord
范围查询支持不支持支持(如range(a..b)
内存占用较高(哈希表需预留空间)较低(B树结构紧凑)
何时选择BTreeMap
  1. 需要元素按键排序(如排行榜、字典序输出)。
  2. 需要范围查询(如查找键在[a, b]之间的所有元素)。
  3. 键类型实现Ord但不实现Hash(如自定义类型未实现Hash)。
  4. 对内存占用较敏感,且插入/查询频率适中(O(log n)可接受)。

示例(BTreeMap范围查询):

use std::collections::BTreeMap;fn main() {let mut btree_map = BTreeMap::new();btree_map.insert(3, "three");btree_map.insert(1, "one");btree_map.insert(2, "two");// 自动按键排序println!("btree_map: {:?}", btree_map); // {1: "one", 2: "two", 3: "three"}// 范围查询(键1到2)let range = btree_map.range(1..=2);for (k, v) in range {println!("{}: {}", k, v); // 1: one, 2: two}
}

64. HashSetBTreeSet的特点,如何判断元素是否存在?

HashSet<T>的特点:
  • 基于HashMap<T, ()>实现,存储唯一元素(无键值对,仅值)。
  • 元素无序,T需实现Hash + Eq trait。
  • 插入、删除、判断存在的平均复杂度为O(1)。
  • 适合快速去重和存在性检查,对顺序无要求。
BTreeSet<T>的特点:
  • 基于BTreeMap<T, ()>实现,元素唯一且按Ord trait排序。
  • T需实现Ord trait。
  • 插入、删除、判断存在的复杂度为O(log n)。
  • 支持范围查询和有序遍历,适合需要排序或范围操作的场景。
判断元素是否存在的方法:

两种集合均通过contains方法判断元素是否存在,返回bool

示例:

use std::collections::{HashSet, BTreeSet};fn main() {// HashSetlet mut hash_set = HashSet::new();hash_set.insert("apple");hash_set.insert("banana");println!("HashSet has 'apple'? {}", hash_set.contains("apple")); // true// BTreeSetlet mut btree_set = BTreeSet::new();btree_set.insert(3);btree_set.insert(1);btree_set.insert(2);println!("BTreeSet has 2? {}", btree_set.contains(&2)); // trueprintln!("BTreeSet elements: {:?}", btree_set); // {1, 2, 3}(有序)
}

65. 什么是“切片(Slice)”?&[T]&str的关系是什么?

切片(Slice)的定义:

切片是一种不拥有所有权的引用类型,用于指向集合中一段连续的元素,格式为&[T](泛型切片)或&str(字符串切片)。它不存储数据,仅包含指针(指向数据起始位置)和长度(元素数量),因此长度在编译时不确定,但访问时会检查边界以避免越界。

切片的特点:
  • 不可变切片(&[T]):不能修改指向的元素。
  • 可变切片(&mut [T]):可以修改指向的元素,但需遵守借用规则(同一时间只能有一个可变引用)。
  • 常用于安全访问集合的部分数据,无需复制整个集合。
&[T]&str的关系:
  • &str&[u8]特化版本,专门用于表示UTF-8编码的字符串切片,保证数据符合UTF-8标准。
  • &[T]是通用的切片类型,可指向任何连续存储的同类型元素(如Vec<T>、数组[T; N])。
  • 两者均为切片,结构相同(指针+长度),但&str有额外的UTF-8有效性约束。

示例:

fn main() {// 数组切片(&[T])let arr = [1, 2, 3, 4, 5];let slice: &[i32] = &arr[1..4]; // 指向arr的索引1到3(元素2,3,4)println!("array slice: {:?}", slice); // [2, 3, 4]// 字符串切片(&str)let s = String::from("hello world");let str_slice: &str = &s[0..5]; // 指向"hello"println!("string slice: {}", str_slice); // hello// &str本质是&[u8]的特化(但保证UTF-8)let bytes: &[u8] = str_slice.as_bytes();println!("bytes: {:?}", bytes); // [104, 101, 108, 108, 111]
}

二、120道Rust面试题目录列表

文章序号Rust面试题120道
1Rust面试题及详细答案120道(01-10)
2Rust面试题及详细答案120道(11-18)
3Rust面试题及详细答案120道(19-26)
4Rust面试题及详细答案120道(27-32)
5Rust面试题及详细答案120道(33-41)
6Rust面试题及详细答案120道(42-50)
7Rust面试题及详细答案120道(51-57)
8Rust面试题及详细答案120道(58-65)
9Rust面试题及详细答案120道(66-71)
10Rust面试题及详细答案120道(72-80)
11Rust面试题及详细答案120道(81-89)
12Rust面试题及详细答案120道(90-98)
13Rust面试题及详细答案120道(99-105)
14Rust面试题及详细答案120道(106-114)
15Rust面试题及详细答案120道(115-120)
http://www.dtcms.com/a/349624.html

相关文章:

  • 解锁处暑健康生活
  • Docker:部署Nginx
  • week4-[一维数组]数码个数
  • Gemini 2.5 Flash-Lite 与 GPT-5-mini:高性能低成本模型,如何选择?
  • 链表OJ习题(1)
  • redis-缓存-持久化
  • 使用 Gemini CLI作为 Claude Code的 subagent
  • OC-MVC模式下的折叠cell
  • 利用 Python 爬虫获取 1688 商品详情 API 返回值说明(代码示例)实战指南
  • 爬虫基础学习-爬取网页项目
  • vue2使用WaveSurfer实现简易的音频播放
  • 波音787项目:AR技术重塑航空制造的数字化转型
  • 用MessageBus优化模块通信:实现订阅/发布模式
  • nmcli命令详解
  • 文吃透朴素贝叶斯:从原理到实战
  • 【python文件处理】使用 open() 函数打开文件、 File 操作文件、使用 OS 对象操作文件目录的知识,使用 open() 函数打开文件
  • DMP-Net:面向脑组织术中成像的深度语义先验压缩光谱重建方法|文献速递-深度学习人工智能医疗图像
  • Android进入Activity时闪黑生命周期销毁并重建
  • 集成电路学习:什么是Caffe深度学习框架
  • 强化学习核心概念与算法详解-马尔可夫决策过程(MDP)+贝尔曼方程(Bellman Equation)
  • 合同管理软件的主要功能有什么?
  • 朴素贝叶斯学习笔记:从原理到实战(J享)
  • (LeetCode 每日一题) 498. 对角线遍历 (矩阵、模拟)
  • SSM从入门到实战:3.2 SpringMVC请求处理与控制器
  • 《C++哈希表:高效数据存储与检索的核心技术》
  • 朴素贝叶斯算法学习总结
  • MySQL 磁盘和 Redis 内存
  • 无人机航拍数据集|第22期 无人机城市交通目标检测YOLO数据集8624张yolov11/yolov8/yolov5可训练
  • Coze用户账号设置修改用户头像-前端源码
  • 【ACP】2025-最新-疑难题解析-5