实现一个使用std::set<int> 权限数组总表, 通过传入用户选择的权限数值,生成一个string,使用|号分割符。最后转为UINT8返回一个数值。
1、C++实现的一个函数
std::vector<uint8_t> make_auth(const std::vector<int>& auth) {
std::string value;
for (int v : auth) {
if (auth_map.find(v) != auth_map.end()) {
value += std::to_string(v);
value += '|';
}
}
if (!value.empty()) {
value.pop_back();
}
return std::vector<uint8_t>(value.begin(), value.end());
}
2、RUST 大部分人使用的方式。性能没有什么太大的区别。代码简单
pub fn make_auth(&self, auth: Vec<i32>) -> Vec<u8> {
let mut value = String::new();
for v in auth {
if self.auth_map.contains(&v) {
value.push_str(&v.to_string());
value.push('|');
}
}
if !value.is_empty() {
value.pop();
}
value.into_bytes()
}
性能瓶颈
-
字符串拼接:
value.push_str(&v.to_string())
每次都会创建一个新的String
,这会导致不必要的内存分配和复制。push
和push_str
的频繁调用可能会导致多次重新分配内存,特别是在auth
向量较大时。
-
最后的分隔符:
- 每次添加
|
分隔符,即使在最后一个元素后也会添加一个分隔符,导致最终字符串末尾多了一个分隔符。
- 每次添加
3、RUST 原生API实现
pub fn make_auth(&self, auth: Vec<i32>) -> Vec<u8> {
let filter_value: Vec<i32> = auth
//获取迭代器
.into_iter()
//过滤出需要的数据
.filter(|&v| self.auth_map.contains(&v))
//一次性分配内存返回数据
.collect();
let v = filter_value
//获取迭代器
.iter()
//转为string
.map(|id| id.to_string())
//一次性分配内存
.collect::<Vec<String>>()
//一次性增加 |
.join("|");
v.into_bytes()
}
- 性能特点:
- 过滤和映射:使用了迭代器的
filter
和map
方法。filter
函数会逐个检查元素是否在auth_map
中,效率取决于auth_map
的实现(例如,哈希表的查找通常是 O(1))。 - 内存分配:这里也会有内存分配,但
collect
会为filtered_value
预分配内存。然后,join
会一次性拼接所有字符串,相对较少的内存分配。
- 过滤和映射:使用了迭代器的
性能比较
-
内存使用:
- 第一个实现由于在循环中多次调用
push_str
,可能会导致较多的内存分配。 - 第二个实现利用了
join
方法一次性拼接,通常更高效。
- 第一个实现由于在循环中多次调用
-
时间复杂度:
- 两个实现的时间复杂度都是 O(n),其中 n 是
auth
的长度。然而,由于第三个实现使用了更高效的内存管理策略(先过滤后拼接),在实际性能上通常会更优。
- 两个实现的时间复杂度都是 O(n),其中 n 是
以上代码,我们如果不增加优化,市面上95%的公司开发人员,会直接采用 【第一种】 的写法。如果采用RUST的开发人员,或其它语言转RUST的开发人员,多数情况采用【第二种】的写法(编程思想很难改变)。深入学习与了解后会采用【第三种】写法。
不是强调谁强,谁弱,C++有很多优秀的轮子,RUST 自身轮子不够多,但是基础轮子性能不错。
C++ 如果自身时间够多,功力够强,可以多花时间来写更优秀的代码。(有稳定的代码,比什么都强)
RUST 各种打破原有开发思维设计方案与奇怪的语法,新手也可以写出更强的代码。RUST FFI与C++配合可以做出非常优秀的软件。各取所需。