【Rust迭代器】Rust迭代器用法解析与应用实战
✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:Rust语言通关之路
景天的主页:景天科技苑
文章目录
- Rust迭代器
- 1. 迭代器基础
- 1.1 什么是迭代器
- 1.2 创建迭代器
- 1.3 使用迭代器
- 2. 迭代器适配器
- 2.1 map
- 2.2 filter
- 2.3 filter_map
- 2.4 flat_map
- 2.5 take和take_while
- 2.6 skip和skip_while
- 2.7 zip
- 2.8 enumerate
- 2.9 chain
- 2.10 cycle
- 3. 消费迭代适配器
- 3.1 collect
- 3.2 fold
- 3.3 any和all
- 3.4 find和position
- 3.6 max和min
- 3.7 sum和product
- 3.8 count
- 3.9 last和nth
- 4. 高级迭代器用法
- 4.1 自定义迭代器
- 4.2 Peekable迭代器
- 4.3 迭代器性能
- 4.4 并行迭代器
- 5. 迭代器性能优化技巧
- 1)避免中间集合:尽量使用迭代器链而不是创建中间集合
- 2)使用for_each代替for循环:在某些情况下可能更高效
- 3)利用短路求值:any和all会在确定结果后立即停止迭代
- 4)选择合适的迭代器:根据需求选择iter()、iter_mut()或into_iter()
- 5)预分配空间:当最终需要集合时,可以预分配空间提高性能
- 6. 常见问题与解决方案
- 1)迭代器被消耗:迭代器是消耗性的,一旦遍历完成就不能再使用
- 2)所有权问题:into_iter()会获取所有权
- 3)无限迭代器:某些迭代器(如cycle)是无限的,需要与take等适配器一起使用
- 4)惰性求值:迭代器是惰性的,只有在消费者调用时才会执行
- 7. 总结
Rust迭代器
迭代器是Rust语言中一个强大且高效的概念,它为处理集合和数据序列提供了统一、安全且零成本抽象的接口。
Rust的迭代器不仅使用方便,而且在编译时就能进行大量优化,使得最终生成的代码性能通常能与手写的循环相媲美。
迭代器模式允许你对一个项的序列进行某些处理。迭代器(iterator)负责遍历序列中的每一项和决定序列何时结束的逻辑。
当使用迭代器时,我们无需重新实现这些逻辑。
1. 迭代器基础
1.1 什么是迭代器
在Rust中,迭代器是实现了Iterator trait的任何类型都是迭代器。这个Iterator trait是标准库中的trait。源码中,这个trait定义如下:
pub trait Iterator {type Item;//type Item和Self::Item这种用法叫做定义trait的关联类型。这个在项目中用的比较多。这个next方法是被要求实现该trait唯一必须要实现的方法,该trait的其他方法是有默认实现fn next(&mut self) -> Option<Self::Item>; // 提供了许多默认方法...
}
next方法是被要求实现该trait唯一必须要实现的方法,该trait的其他方法是有默认实现
实例对象每调用一次next方法,返回一个元素,当迭代器结束时,返回None。
任何实现了Iterator trait的类型都可以被迭代,产生一系列值。
1.2 创建迭代器
Rust中的大多数集合类型都提供了创建迭代器的方法:
fn main() {// 创建迭代器,迭代器是实现了Iterator trait的对象// 通过集合创建迭代器let mut vec = vec![1, 2, 3];// 获取不可变引用迭代器let iter = vec.iter(); // 产生 &i32// 获取可变引用迭代器let iter_mut = vec.iter_mut(); // 产生 &mut i32// 获取所有权迭代器let into_iter = vec.into_iter(); // 产生 i32
}
创建可变引用迭代器
//创建mutable迭代器
let mut vec = vec![1, 2, 3];
for num in vec.iter_mut() {*num += 1;println!("{}", num);
}
创建获取所有权迭代器
//创建获取所有权的迭代器
let vec = vec![1, 2, 3];
for num in vec.into_iter() {println!("{}", num);
}
println!("{:?}", vec); // 错误!vec的所有权已移动到迭代器中
在 Rust 中,迭代器是 惰性的(lazy),这意味着直到调用方法消费迭代器之前它都不会有效果。
1.3 使用迭代器
创建迭代器之后,可以选择用多种方式利用它。
最简单的使用方式是for循环:
fn main() {let vec = vec![1, 2, 3];//使用迭代器for num in vec.iter() {println!("{}", num);}
}
使用for_each代替for循环:在某些情况下可能更高效
//for_each
let nums = vec![1, 2, 3, 4, 5];
//for_each方法会遍历迭代器中的所有元素,并对每个元素执行闭包
nums.iter().for_each(|x| println!("{}", x));
也可以手动调用next()方法:
返回的是Option
let mut iter = vec![1, 2, 3].iter();
//手动调用next方法
println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());
当迭代器结束时,返回None
2. 迭代器适配器
Rust提供了丰富的迭代器适配器方法,可以对迭代器进行各种转换和组合。
2.1 map
map对每个元素应用一个函数:
let nums = vec![1, 2, 3];
let squares: Vec<_> = nums.iter().map(|x| x * x).collect();
println!("{:?}", squares);
2.2 filter
filter只保留满足条件的元素:
let nums = vec![1, 2, 3, 4, 5];
let evens: Vec<_> = nums.iter().filter(|x| *x % 2 == 0).collect();
println!("{:?}", evens);
2.3 filter_map
结合了filter和map的功能:
filter_map 会调用 parse 方法,如果成功则返回 Some,失败则返回 None
let strings = vec!["3", "seven", "8", "nine"];
let numbers: Vec<i32> = strings.iter().filter_map(|s| s.parse().ok()).collect();
println!("{:?}", numbers);
2.4 flat_map
将每个元素转换为迭代器后展平
flat_map 会将每个单词的字符展开成一个迭代器,然后将这些迭代器连接起来
let words = vec!["hello", "world"];
let letters: Vec<_> = words.iter().flat_map(|w| w.chars()).collect();
println!("{:?}", letters);
2.5 take和take_while
take获取前n个元素:
在Rust中,Iterator 类型的 take(n) 方法是用来创建一个新的迭代器,这个新的迭代器将只包含原始迭代器的前 n 个元素。这意味着原始迭代器不会被消耗掉,你可以在之后再次使用它。
//take
let numbers = vec![1, 2, 3, 4, 5];// 使用 take 方法,获取前3个元素
let iter = numbers.iter().take(3);// 遍历新的迭代器
for number in iter {println!("{}", number);
}// 原始迭代器仍然可以再次使用
for number in numbers.iter() {println!("{}", number);
}
take_while获取满足条件的连续元素:
//take_while
let numbers = vec![1, 2, 3, 4, 5];// 使用 take_while 方法,获取满足条件小于3的元素
// take_while 会返回一个新的迭代器,这个迭代器会从原始迭代器中获取元素,直到满足条件为止
let iter = numbers.iter().take_while(|x| **x < 3);// 遍历新的迭代器
for number in iter {println!("{}", number);
}
2.6 skip和skip_while
与take相反,跳过元素:
//skip
let numbers = vec![1, 2, 3, 4, 5];// 使用 skip 方法,跳过前3个元素
let iter = numbers.iter().skip(3);// 遍历新的迭代器
for number in iter {println!("{}", number);
}//skip_while
let numbers = vec![1, 2, 3, 4, 5];// 使用 skip_while 方法,跳过满足条件小于3的元素
let iter = numbers.iter().skip_while(|x| **x < 3);// 遍历新的迭代器
for number in iter {println!("{}", number);
}
2.7 zip
将两个迭代器合并为一个元组迭代器:
//zip
let numbers = vec![1, 2, 3, 4, 5];
let letters = vec!['a', 'b', 'c', 'd', 'e'];// 使用 zip 方法,将两个迭代器组合成一个元组迭代器
let iter = numbers.iter().zip(letters.iter());// 遍历新的迭代器
for (number, letter) in iter {println!("{} - {}", number, letter);
}
2.8 enumerate
为每个元素添加索引:
//enumerate
let numbers = vec![1, 2, 3, 4, 5];// 使用 enumerate 方法,获取索引和元素
let iter = numbers.iter().enumerate();// 遍历新的迭代器
for (index, number) in iter {println!("{} - {}", index, number);
2.9 chain
连接两个迭代器:
注意:chain只能连接相同类型的迭代器
//chain
//注意:chain只能连接相同类型的迭代器
let numbers = vec![1, 2, 3];
let letters = vec![4, 5, 6];// 使用 chain 方法,将两个迭代器连接起来
let iter = numbers.iter().chain(letters.iter());// 遍历新的迭代器
for item in iter {println!("{}", item);
}
2.10 cycle
无限循环迭代器:
//cycle
let numbers = vec![1, 2, 3];// 使用 cycle 方法,将迭代器循环起来
let iter = numbers.iter().cycle(); // cycle会无限循环迭代器// 遍历新的迭代器
for (index, item) in iter.enumerate() {//设置个退出条件,否则会无限循环if index > 10 {break;}println!("{}", item);
}
3. 消费迭代适配器
消费者是消耗迭代器并产生最终结果的方法。
3.1 collect
将迭代器转换为集合:
let nums = 1..=5;
let squared: Vec<i32> = nums.map(|x| x * x).collect();
println!("{:?}", squared);
3.2 fold
累积计算:
//fold
//fold求和
let nums = 1..=5;
let sum = nums.fold(0, |acc, x| acc + x);println!("{}", sum);//使用fold求平均值
let nums = vec![1, 2, 3, 4, 5];
let avg = nums.iter().fold(0.0, |acc, x| acc + (*x as f64)) / (nums.len() as f64);println!("{}", avg);
3.3 any和all
检查是否存在或所有元素满足条件:
//any
let nums = vec![1, 2, 3, 4, 5];
//any方法会返回true或false,表示迭代器中任意一个元素满足条件即可
let has_even = nums.iter().any(|x| x % 2 == 0);println!("{}", has_even);//all
//all方法会返回true或false,表示迭代器中所有元素都满足条件才返回true
let nums = vec![1, 2, 3, 4, 5];
let all_even = nums.iter().all(|x| x % 2 == 0);println!("{}", all_even);
3.4 find和position
find和position都会返回Option
查找元素:
//find 返回的是满足条件的元素的引用Option
let nums = vec![1, 2, 3, 4, 5];
//find方法会返回Option,表示迭代器中找到的第一个满足条件的元素
let first_even = nums.iter().find(|x| **x % 2 == 0);//find方法返回Option,所以需要使用unwrap_or_else来处理None的情况
let first_even = first_even.unwrap_or_else(|| &0);
println!("{:?}", first_even);//position。返回的是索引Option
let nums = vec![1, 2, 3, 4, 5];
//position方法会返回Option,表示迭代器中找到的第一个满足条件的元素的索引
let first_even_index = nums.iter().position(|x| *x % 2 == 0);//position方法返回Option,所以需要使用unwrap_or_else来处理None的情况
let first_even_index = first_even_index.unwrap_or_else(|| 0);
println!("{:?}", first_even_index);
3.6 max和min
查找最大最小值:
返回的也是Option
//max
let nums = vec![1, 2, 3, 4, 5];
//max方法会返回Option,表示迭代器中最大的元素
let max = nums.iter().max();//max方法返回Option,所以需要使用unwrap_or_else来处理None的情况
let max = max.unwrap_or_else(|| &0);
println!("{:?}", max);//min
let nums = vec![1, 2, 3, 4, 5];
//min方法会返回Option,表示迭代器中最小的元素
let min = nums.iter().min();//min方法返回Option,所以需要使用unwrap_or_else来处理None的情况
let min = min.unwrap_or_else(|| &0);
println!("{:?}", min);
3.7 sum和product
求和与求积:
//sum
let nums = vec![1, 2, 3, 4, 5];
//sum方法会返回迭代器中所有元素的和
let sum = nums.iter().sum::<i32>(); //sum方法需要指定返回值的类型,在变量处标注类型也可以
println!("{:?}", sum);//product
let nums = vec![1, 2, 3, 4, 5];
//product方法会返回迭代器中所有元素的积
let product = nums.iter().product::<i32>(); //product方法需要指定返回值的类型,在变量处标注类型也可以
println!("{:?}", product);
3.8 count
计算元素数量:
//count
let nums = vec![1, 2, 3, 4, 5];
//count方法会返回usize,表示迭代器中所有元素的数量
let count = nums.iter().count();
println!("{:?}", count);
3.9 last和nth
last: 表示获取迭代器中最后一个元素
nth: 表示获取迭代器中第n个元素,n表示索引位置
//last
let nums = vec![1, 2, 3, 4, 5];
//last方法会返回Option,表示迭代器中最后一个元素
let last = nums.iter().last();//last方法返回Option,所以需要使用unwrap_or_else来处理None的情况
let last = last.unwrap_or_else(|| &0);
println!("{:?}", last);//nth
let nums = vec![1, 2, 3, 4, 5];
//nth方法会返回Option,表示迭代器中第n个元素,n从0开始
let third = nums.iter().nth(2);//nth方法返回Option,所以需要使用unwrap_or_else来处理None的情况
let third = third.unwrap_or_else(|| &0);
println!("{:?}", third);
4. 高级迭代器用法
4.1 自定义迭代器
我们可以实现自己的迭代器类型:
//自定义迭代器
struct Counter {count: u32,max: u32,
}impl Counter {fn new(max: u32) -> Counter {Counter { count: 0, max }}
}
//自定义迭代器,只需要我们创建的类实现Iterator这个trait即可
impl Iterator for Counter {type Item = u32; //type Item = u32;表示迭代器中元素的类型,在trait中定义//next方法是Iterator trait中定义的,我们需要实现它//next方法的返回值是Option<Self::Item>,表示迭代器中下一个元素,如果迭代器中没有下一个元素,则返回None//next方法的参数是&mut self,表示迭代器的可变引用,因为迭代器需要在每次调用next方法时修改内部的状态//Self::Item表示迭代器中元素的类型,我们在上面定义为u32fn next(&mut self) -> Option<Self::Item> {//如果计数器小于最大值,则增加计数器并返回Some(self.count),否则返回Noneif self.count < self.max {self.count += 1;Some(self.count)} else {None}}
}
fn main() {//创建Counter实例,传的参数是最大值let counter = Counter::new(5);//for循环会自动调用迭代器的next方法,直到迭代器返回Nonefor num in counter {println!("{}", num);}
}
4.2 Peekable迭代器
peekable允许我们查看下一个元素而不消耗它:
eekable 是 Rust 迭代器的一个适配器方法,它可以将任何迭代器转换为可以"偷看"下一个元素的迭代器。
这个功能在很多场景下非常有用,特别是当你需要基于下一个元素的值来决定当前如何处理时。
基本用法
let mut iter = [1, 2, 3].iter().peekable();
主要使用场景
- 前瞻性处理(Look-ahead Processing)
当需要根据下一个元素决定当前元素如何处理时:
let numbers = [1, 2, 3, 4, 5];
let mut iter = numbers.iter().peekable();while let Some(num) = iter.next() {if let Some(&&next_num) = iter.peek() {println!("当前: {}, 下一个: {}", num, next_num);} else {println!("当前: {}, 这是最后一个", num);}
}
- 合并连续重复项
处理连续重复的元素:
fn dedup_adjacent<I: Iterator<Item = i32>>(iter: I) -> impl Iterator<Item = i32> {let mut peekable = iter.peekable();std::iter::from_fn(move || {while let Some(current) = peekable.next() {if peekable.peek() != Some(¤t) {return Some(current);}}None})
}
- 解析器和词法分析器
在编写解析器时经常需要前瞻:
fn tokenize(input: &str) -> Vec<Token> {let mut chars = input.chars().peekable();let mut tokens = Vec::new();while let Some(c) = chars.next() {match c {'0'..='9' => {let mut num = c.to_string();while let Some('0'..='9') = chars.peek() {num.push(chars.next().unwrap());}tokens.push(Token::Number(num.parse().unwrap()));}// 其他token处理...}}tokens
}
- 条件性跳过元素
基于后续元素决定是否跳过当前元素:
let mut iter = [1, 2, 3, 4, 5].iter().peekable();
let mut result = Vec::new();while let Some(&num) = iter.next() {if num == 3 && iter.peek() == Some(&&4) {// 跳过3如果下一个是4continue;}result.push(num);
}
- 分隔符处理
处理以特定模式分隔的数据:
fn split_by_double_newline(text: &str) -> Vec<&str> {let mut lines = text.lines().peekable();let mut paragraphs = Vec::new();let mut current = String::new();while let Some(line) = lines.next() {current.push_str(line);if lines.peek() == Some(&"") {paragraphs.push(current);current = String::new();lines.next(); // 跳过空行}}if !current.is_empty() {paragraphs.push(current);}paragraphs
}
Peekable的重要方法
Peekable 迭代器提供了几个特有方法:
1)peek() - 返回下一个元素的引用但不消耗它
if iter.peek() == Some(&value) { … }
2)next() - 返回下一个元素并且消耗它
let next = iter.next();
3)next_if() - 条件性消耗下一个元素
// 只有当下一个元素匹配谓词时才消耗它
while let Some(item) = iter.next_if(|&x| x > 5) { … }
4)next_if_eq() - 只有当下一个元素等于给定值时才消耗它
// 只有当下一个元素是5时才消耗它
if let Some(five) = iter.next_if_eq(&5) { … }
示例:
//peekable
let nums = vec![1, 2, 3, 4, 5];
//peekable方法会返回一个Peekable迭代器,这个迭代器可以预览下一个元素,但是不会消费下一个元素
let mut iter = nums.iter().peekable();//peek方法会返回Option,表示预览下一个元素,但是不会消费下一个元素
let next = iter.peek();
println!("{:?}", next);//next方法会返回Option,表示获取下一个元素,并消费这个元素
let next = iter.next();
println!("{:?}", next);//再次调用peek方法,会返回下一个元素的引用,因为上一次调用next方法已经消费了上一个元素
let next = iter.peek();
println!("{:?}", next);
4.3 迭代器性能
Rust迭代器是零成本抽象,编译器能将其优化为高效的代码。例如:
let sum: i32 = (1…=100).filter(|x| x % 2 == 0).sum();
编译器会将其优化为类似手写循环的代码,而不会有额外的开销。
4.4 并行迭代器
需要在项目中安装第三方库
cargo add rayon
使用rayon库可以实现并行迭代:
//并行迭代器
use rayon::prelude::*;
fn main() {//使用并行迭代器let sum: u128 = (1..=100000).into_par_iter().filter(|x| x % 2 == 0) //过滤出偶数.sum(); //求和println!("{}", sum);
}
5. 迭代器性能优化技巧
1)避免中间集合:尽量使用迭代器链而不是创建中间集合
// 不好
let filtered: Vec<_> = nums.iter().filter(|x| x % 2 == 0).collect();
let doubled: Vec<_> = filtered.iter().map(|x| x * 2).collect();// 好
let result: Vec<_> = nums.iter().filter(|x| x % 2 == 0).map(|x| x * 2).collect();
2)使用for_each代替for循环:在某些情况下可能更高效
(0..100).for_each(|x| println!("{}", x));
3)利用短路求值:any和all会在确定结果后立即停止迭代
4)选择合适的迭代器:根据需求选择iter()、iter_mut()或into_iter()
5)预分配空间:当最终需要集合时,可以预分配空间提高性能
let mut result = Vec::with_capacity(100);
(0..100).map(|x| x * 2).for_each(|x| result.push(x));
6. 常见问题与解决方案
1)迭代器被消耗:迭代器是消耗性的,一旦遍历完成就不能再使用
let mut iter = vec![1, 2, 3].into_iter();
iter.next(); // 消耗第一个元素
let sum: i32 = iter.sum(); // 只会计算剩下的元素
2)所有权问题:into_iter()会获取所有权
一旦使用了into_iter(),原数据将不可再使用
let vec = vec![1, 2, 3];
let iter = vec.into_iter(); // vec的所有权被转移
// 这里不能再使用vec
3)无限迭代器:某些迭代器(如cycle)是无限的,需要与take等适配器一起使用
let first_ten = (0..).cycle().take(10).collect::<Vec<_>>();
4)惰性求值:迭代器是惰性的,只有在消费者调用时才会执行
let iter = (0..10).map(|x| {println!("Processing {}", x);x * 2
}); // 这里不会打印任何东西let result: Vec<_> = iter.collect(); // 现在才会执行
7. 总结
Rust的迭代器是一个强大而灵活的工具,它提供了高效、安全的方式来处理各种数据序列。
通过本文的学习,相信大家应该已经掌握了迭代器的基本用法、各种适配器和消费者方法,以及如何在实际项目中应用它们。
迭代器不仅能写出更简洁、更表达性的代码,还能保持高性能,这是Rust语言"零成本抽象"哲学的重要体现。
记住,熟练掌握迭代器需要实践。尝试在你们自己的Rust项目中使用迭代器,开始时可能会遇到一些困难,但随着经验的积累,你会越来越欣赏它们带来的便利和效率。
相关文章:
【Rust迭代器】Rust迭代器用法解析与应用实战
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
嵌入式学习笔记DAY23(树,哈希表)
一、树 1.树的概念 之前我们一直在谈的是一对一的线性结构,现实中,还存在很多一对多的情况需要处理,一对多的线性结构——树。 树的结点包括一个数据元素及若干指向其子树的分支,结点拥有的子树数称为结点的度。度为0的结点称为叶…...
操作系统————五种页面置换算法(OPT,FIFO,LRU,NRU,加强版NRU)大总结
❤️❤️❤️算法1:最佳置换算法(OPT) 算法思想: 值得注意的是这是一种理想型算法,实际上并不可能实现,读者需要注意 下面我们来解析一下它的原理: 我们假设有三个内存块,对于页面…...
数据结构(二) 线性表
一. 线性表 1.定义 线性表是由n(n>0)个具有相同数据类型的数据元素构成的有限序列。其中,元素之间通过顺序关系排列,每个元素有且只有一个直接前驱和一个直接后继(除首尾元素外) 二.线性表的顺序表示(顺序表) 1.存储方式 使用连续的内存空间(数组)存储…...
TS04:高性能四通道自动灵敏度校准电容触摸传感器
在现代电子设备中,电容触摸传感器的应用越来越广泛,而高性能的传感器芯片是实现良好用户体验的关键。 TS04 四通道电容触摸传感器,凭借其自动灵敏度校准功能和多种特性,成为理想的解决方案。本文将简要介绍 TS04 的主要特性、功能…...
鸿蒙 系统-安全-程序访问控制-应用权限管控
Ability Kit 提供了一种允许应用访问系统资源(如:通讯录等)和系统能力(如:访问摄像头、麦克风等)的通用权限访问方式,来保护系统数据(包括用户个人数据)或功能࿰…...
ArcGIS Pro 3.4 二次开发 - 框架
环境:ArcGIS Pro SDK 3.4 .NET 8 文章目录 框架1 框架1.1 如何在 DockPane 可见或隐藏时订阅和取消订阅事件1.2 执行命令1.3 设置当前工具1.4 激活选项卡1.5 激活/停用状态 - 修改条件1.6 判断应用程序是否繁忙1.7 获取应用程序主窗口1.8 关闭 ArcGIS Pro1.9 获取 …...
打破传统仓库管理困局:WMS如何重构出入库全流程
引言 在制造业与零售业高速发展的今天,仓库管理仍普遍面临效率低、错发漏发频发、库存数据滞后等痛点。人工登记导致30%的错单率,货位混乱让拣货耗时增加50%,而账实不符引发的二次采购成本更吞噬着企业利润。如何突破传统管理桎梏࿱…...
npm 安装时 SSL 证书过期问题笔记
问题描述: npm error code CERT_HAS_EXPIRED npm error errno CERT_HAS_EXPIRED npm error request to https://registry.npm.taobao.org/axios failed, reason: certificate has expired 这表明当前配置的 npm 镜像源(淘宝镜像 https://registry.npm.taobao.org&…...
【大数据】MapReduce 编程-- PageRank--网页排名算法,用于衡量网页“重要性”-排序网页
PageRank 是 Google 创始人拉里佩奇(Larry Page)和谢尔盖布林(Sergey Brin)在 1998 年提出的一种网页排名算法,用于衡量网页“重要性”的一种方式。它是搜索引擎中用于排序网页的一种基础算法 一个网页越是被其他重要…...
Craw4AI:LLM友好的网页爬虫
GitHub:https://github.com/unclecode/crawl4ai 更多AI开源软件:发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Crawl4AI旨在让网页爬取和数据提取变得简单而高效。无论构建复杂的 AI 应用程序还是增强大语言模型,Crawl4AI 都能…...
idea 安装飞算-javaAI 插件使用
文章目录 前言idea 安装飞算-javaAI 插件使用1. 介绍一下飞算-AI2. 安装使用 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差,实在白嫖的…...
Lombok
Lombok Lombok 是一个 Java 库,通过注解自动生成样板代码(如 Getter/Setter、构造函数等),从而简化开发。在你提供的代码中,AllArgsConstructor 就是一个 Lombok 注解。以下是 Lombok 常用注解及其作用的详细说明&…...
起点与破圈
写了多年代码,我为什么开始转向算法,直到如今投身于大模型领域? 作为一名拥有 10 年经验的开发者,我的职业路径几乎覆盖了技术发展的多个阶段。从最早使用 Flask/Django 开发网站,到后来构建大数据系统、设计服务器架…...
基于AI的Web数据管道,使用n8n、Scrapeless和Claude
引言 在当今数据驱动的环境中,组织需要高效的方法来提取、处理和分析网络内容。传统的网络抓取面临着诸多挑战:反机器人保护、复杂的JavaScript渲染以及持续的维护需求。此外,理解非结构化的网络数据则需要复杂的处理能力。 本指南演示了如…...
7GB显存如何部署bf16精度的DeepSeek-R1 70B大模型?
构建RAG混合开发---PythonAIJavaEEVue.js前端的实践-CSDN博客 服务容错治理框架resilience4j&sentinel基础应用---微服务的限流/熔断/降级解决方案-CSDN博客 conda管理python环境-CSDN博客 快速搭建对象存储服务 - Minio,并解决临时地址暴露ip、短链接请求改…...
初识函数------了解函数的定义、函数的参数、函数的返回值、说明文档的书写、函数的嵌套使用、变量的作用域(全局变量与局部变量)
文章目录 一、什么是函数?二、函数定义与调用2.1 基本语法2.2 示例演示 三、函数参数详解3.1 位置参数3.2 默认参数3.3 可变参数3.4 关键字参数 四、返回值与文档说明4.1 返回多个值4.2 编写文档字符串 五、函数嵌套与作用域5.1 嵌套函数示例5.2 变量作用域5.3 glob…...
Java常见API文档(下)
格式化的时间形式的常用模式对应关系如下: 空参构造创造simdateformate对象,默认格式 练习.按照指定格式展示 package kl002;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;public class Date3 {publi…...
ubuntu 20.04 ping baidu.coom可以通,ping www.baidu.com不通 【DNS出现问题】解决方案
ping baidu.coom可以通,ping www.baidu.com不通【DNS出现问题】解决方案 检查IPV6是否有问题 # 1. 检查 IPv6 地址,记住网络接口的名称 ip -6 addr show# 2. 测试本地 IPv6,eth0换成自己的网络接口名称 ping6 ff02::1%eth0# 3. 检查路由 ip…...
Oracle 中 open_cursors 参数详解:原理、配置与性能测试
#Oracle #参数 # open_cursors #ORA-01000 在 Oracle 数据库的众多参数中,open_cursors是一个对应用程序性能和资源管理有着重要影响的参数。它直接关系到数据库与应用程序之间游标资源的使用与分配,合理配置open_cursors参数,能够避免应用程…...
线程调度与单例模式:wait、notify与懒汉模式解析
一.wait 和 notify(等待 和 通知) 引入 wait notify 就是为了能够从应用层面,干预到多个不同线程代码的执行顺序,可以让后执行的线程主动放弃被调度的机会,等先执行的线程完成后通知放弃调度的线程重新执行。 自助取…...
AGI大模型(27):LangChain向量存储
1 安装依赖 使用一个简单的本地向量存储 FAISS,首先需要安装它 pip install faiss-cpu -i https://pypi.tuna.tsinghua.edu.cn/simple pip install langchain_community==0.3.7 -i https://pypi.tuna.tsinghua.edu.cn/simple 由于演示过程中用到了爬虫,需要安装依赖库,如…...
Qwen3 - 0.6B与Bert文本分类实验:深度见解与性能剖析
Changelog [25/04/28] 新增Qwen3-0.6B在Ag_news数据集Zero-Shot的效果。新增Qwen3-0.6B线性层分类方法的效果。调整Bert训练参数(epoch、eval_steps),以实现更细致的观察,避免严重过拟合的情况。 TODO: 利用Qwen3-0.6…...
Oracle 的 PGA_AGGREGATE_LIMIT 参数
Oracle 的 PGA_AGGREGATE_LIMIT 参数 基本概念 PGA_AGGREGATE_LIMIT 是 Oracle 数据库 12c 引入的一个重要内存管理参数,用于限制所有服务器进程使用的 PGA(Program Global Area)内存总量。 参数作用 硬性限制:设置 PGA 内存使…...
# idea 中如何将 java 项目打包成 jar 包?
idea 中如何将 java 项目打包成 jar 包? 例如如何将项目dzs168-dashboard-generate打包成 dzs168-dashboard-generate.jar 1、打开项目结构 Project Structure 在IDEA的顶部菜单栏中选择【File】,然后选择【Project Structure】(或者使用快…...
JVM(Java 虚拟机)深度解析
JVM(Java 虚拟机)深度解析 作为 Java 生态系统的核心,JVM(Java Virtual Machine)是 Java 语言 "一次编写,到处运行" 的关键。它不仅是 Java 程序的运行环境,更是一个复杂的系统软件&…...
算法题(150):拼数
审题: 本题需要我们将数组中的数据经过排序,使得他们拼接后得到的数是所有拼接方案中最大的 思路: 方法一:排序贪心 贪心策略1:直接排序 如果我们直接按照数组数据的字典序进行排序,会导致部分情况出错 eg&…...
怎么样进行定性分析
本文章将教会你如何对实验结果进行定性分析,其需要一定的论文基础,文末有论文撰写小技巧,不想看基础原理的人可以直接调到文章末尾。 一、什么是定性分析 定性分析是一种在众多领域广泛应用的研究方法,它致力于对事物的性质、特…...
RLᵛ_ Better Test-Time Scaling by Unifying LLM Reasoners With Verifiers
RLᵛ: Better Test-Time Scaling by Unifying LLM Reasoners With Verifiers 在人工智能领域,大语言模型(LLM)的推理能力提升一直是研究热点。今天要解读的论文提出了一种全新的强化学习框架RLᵛ,通过融合推理与验证能力…...
关于百度地图JSAPI自定义标注的图标显示不完整的问题(其实只是因为图片尺寸问题)
下载了几个阿里矢量图标库里的图标作为百度地图的自定义图标,结果百度地图显示的图标一直不完整。下载的PNG图标已经被正常引入到前端代码,anchor也设置为了图标底部中心,结果还是显示不完整。 if (iconUrl) {const icon new mapClass.Icon(…...
海思22AP70集超强算力、4K60编解码与多元特性于一体的智能SoC可替代3559V200、3516AV300、3556A
嘿,朋友们!在这个对视觉效果有着极致追求的时代,海思半导体带着满满的诚意,为大家呈上一款堪称惊艳的专业超高清智能网络录像机SoC——22AP70,它就像一颗闪耀的科技新星,即将在各个领域掀起一场视觉革命&am…...
网络协议之一根网线就能连接两台电脑?
写在前面 ~~~~ 如果有两台电脑,通过一根网线可以实现网络互通吗?三台电脑呢?N台电脑呢?本文就以此作为主线来看下吧! 1:正文 ~~~~ 如标题,一根网线就能连接两台电脑?答案是肯定的&a…...
为 Windows 和 Ubuntu 中设定代理服务器的详细方法
有时下载大模型总是下载不出来,要配置代理才行 一、Windows代理设置 ① 系统全局代理设置 打开【设置】→【网络和Internet】→【代理】。 在【手动设置代理】下,打开开关,输入: 地址:10.10.10.215 端口:…...
cmd里可以使用npm,vscode里使用npm 报错
cmd里可以使用npm,vscode里使用npm 报错 报错提示原因解决方法 报错提示 npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系 统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/ fwlink/?LinkID135170 中的 about_Executi…...
MySQL数据库基础 -- SQL 语句的分类,存储引擎
目录 1. 什么是数据库 2. 基本使用 2.1 进入 mysql 2.2 服务器、数据库以及表的关系 2.3 使用案例 2.4 数据逻辑存储 3. SQL 语句分类 4. 存储引擎 4.1 查看存储引擎 4.2 存储引擎的对比 1. 什么是数据库 安装完 MySQL 之后,会有 mysql 和 mysqld。 MySQL …...
设置windows10同时多用户登录方法
RDP wrapper 的版本更新停止在2017年, 找到网上其它大神更新的软件, 参考:RDPWrap v1.8.9.9 (Windows家庭版开启远程桌面、Server解除远程数量限制) - 吾爱破解 - 52pojie.cn 我的需求是在离线环境中布置,方法是&…...
【hive】hive内存dump导出hprof文件
使用jmap -dump:live,formatb,file命令 hive-metastore-heap-eval.sh文件 # if want hiveserver2 ,should grep "org.apache.hive.service.server.HiveServer2" # get pid pidps -ef | grep "org.apache.hadoop.hive.metastore.HiveMetaStore" | grep &qu…...
专题讨论3:基于图的基本原理实现走迷宫问题
问题描述 迷宫通常以二维矩阵形式呈现,矩阵中的元素用 0 和 1 表示,其中 0 代表通路,1 代表墙壁 。存在特定的起点和终点坐标,目标是从起点出发,寻找一条能够到达终点的路径。 实现思路 将迷宫中的每个可通行单元格…...
Linux基础第四天
系统之间文件共享 想要实现两个不同的系统之间实现文件共享,最简单的一种方案就是设置VMware软件的共享文件夹,利用共享文件夹可以实现linux系统和windows系统之间的文件共享,这样就可以实现在windows系统上编辑程序,然后在linux系…...
eNSP中单臂路由器配置完整实验及命令解释
单臂路由器(Router on a Stick)是一种通过单个物理接口处理多个VLAN间路由的解决方案 单臂路由器通过以下方式工作: 交换机端口配置为Trunk模式,允许多个VLAN流量通过路由器子接口为每个VLAN创建虚拟接口每个子接口配置对应VLAN…...
TeaType 奶茶性格占卜机开发记录:一场俏皮的 UniApp 单页奇遇
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 最近我突发奇想,想用 UniApp 做一个轻松又俏皮的小工具,叫做「TeaType 奶茶性格占卜机」…...
AI神经网络降噪 vs 传统单/双麦克风降噪的核心优势对比
1. 降噪原理的本质差异 对比维度传统单/双麦克风降噪AI神经网络降噪技术基础基于固定规则的信号处理(如谱减法、维纳滤波)基于深度学习的动态建模(DNN/CNN/Transformer)噪声样本依赖预设有限噪声类型训练数据覆盖数十万种真实环境…...
【Nginx学习笔记】:Fastapi服务部署单机Nginx配置说明
服务部署单机Nginx配置说明 服务.conf配置文件: upstream asr_backend {server 127.0.0.1:8010; }server {listen 80;server_name your_domain.com;location / {proxy_pass http://localhost:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remot…...
JAVA Web 期末速成
一、专业术语及名词 1. Web 的特点 定义:web 是分布在全世界,基于 HTTP 通信协议,存储在 Web 服务器中的所有相互链接的超文本集 Web 是一种分布式超媒体系统Web 是多媒体化 和 易于导航的Web 与平台无关Web 是动态、交互的 2. TCP/IP 结…...
iOS:重新定义移动交互,引领智能生活新潮流
在当今智能手机与移动设备充斥的时代,操作系统作为其 “灵魂”,掌控着用户体验的方方面面。iOS 系统,这一由苹果公司精心雕琢的杰作,自诞生起便以独特魅力与卓越性能,在移动操作系统领域独树一帜,深刻影响着…...
LabVIEW数据库使用说明
介绍LabVIEW如何在数据库中插入记录以及执行 SQL 查询,适用于对数据库进行数据管理和操作的场景。借助 Database Connectivity Toolkit,可便捷地与指定数据库交互。 各 VI 功能详述 左侧 VI 功能概述:实现向数据库表中插入数据的操作。当输入…...
Linux多进程 写时拷贝 物理地址和逻辑地址
如果不采用写时拷贝技术 直接fork子进程 会发生什么? 如上图所示 橙色为父进程所占内存空间 绿色为子进程所占内存空间。 如果子进程只是需要做出一点点和父进程不一样的 其余和父进程均为相同 第一 就会出现复制开销比较大;第二占用内存空间 所以 …...
在 CentOS 7.9 上部署 node_exporter 并接入 Prometheus + Grafana 实现主机监控
文章目录 在 CentOS 7.9 上部署 node_exporter 并接入 Prometheus Grafana 实现主机监控环境说明node_exporter 安装与配置下载并解压 node_exporter创建 Systemd 启动服务验证服务状态验证端口监听 Prometheus 配置 node_exporter 监控项修改 prometheus.yml重新加载 Prometh…...
Java 反射(Reflection)技术
反射是 Java 提供的一种强大机制,允许程序在运行时(Runtime)动态地获取类的信息、操作类的属性和方法。这种能力使得 Java 程序可以突破编译时的限制,实现更灵活的设计。 一、反射的核心概念 1. 什么是反射 反射是指在程序运行…...
【SpringBoot】从零开始全面解析SpringMVC (三)
本篇博客给大家带来的是SpringBoot的知识点, 本篇是SpringBoot入门, 介绍SpringMVC相关知识. 🐎文章专栏: JavaEE进阶 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,…...