advance/functional-programing/iterator #694
Replies: 19 comments 23 replies
-
萌新可以提个小建议吗? |
Beta Was this translation helpful? Give feedback.
-
typo 问题: 多了多 |
Beta Was this translation helpful? Give feedback.
-
use std::collections::HashMap;
fn main() {
let names = ["sunface", "sunfei"];
let ages = [18, 18];
let folks: HashMap<_, _> = names.into_iter().zip(ages.into_iter()).collect();
println!("{:#?}", names);
println!("{:#?}", ages);
println!("{:#?}", folks);
} |
Beta Was this translation helpful? Give feedback.
-
vec里面只有1,2,3 为什么sum是6 |
Beta Was this translation helpful? Give feedback.
-
高阶内容学习老费劲了,每一个板块都要一两天 |
Beta Was this translation helpful? Give feedback.
-
let result = match IntoIterator::into_iter(values) { |
Beta Was this translation helpful? Give feedback.
-
为什么 c 是不可变的变量 但在for循环中 c.count 可以发生改变 |
Beta Was this translation helpful? Give feedback.
-
这边提一下最后提及的循环展开(Loop Unrolling)和向量化是什么意思,首先阐明概念,循环展开是向量化的一种,向量化还包括有用SSE指令集这里不赘述 #include <stdio.h>
#include <windows.h>
#pragma comment(lib, "Winmm.lib") // for timeGetTime()
#define N 1000000000
int main() {
DWORD start, end;
start = timeGetTime();
int *a = (int *)malloc(N * sizeof(int));
// conventional loop
for (int i = 0; i < N; i++) {
a[i] = i;
}
end = timeGetTime();
printf("Conventional loop time: %d ms\n", end - start);
start = timeGetTime();
// unrolled loop
for (int i = 0; i < N; i += 4) {
a[i] = i;
a[i + 1] = i + 1;
a[i + 2] = i + 2;
a[i + 3] = i + 3;
}
end = timeGetTime();
printf("Unrolled loop time: %d ms\n", end - start);
return 0;
} 第二段unrolled loop耗时约为第一段未展开的1/4左右,因为循环中4个语句之间互不影响,所以编译器优化让他们同步执行 |
Beta Was this translation helpful? Give feedback.
-
fn sum_iter(x: &[f64]) -> f64 {
x.iter().sum::<f64>()
} 这里的 |
Beta Was this translation helpful? Give feedback.
-
学到这里 写GO 的又流下了眼泪 |
Beta Was this translation helpful? Give feedback.
-
虽然 但是, js里 for ... of 才是针对可迭代对象的语法 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
感觉拿js的for of对比更像一点 |
Beta Was this translation helpful? Give feedback.
-
转移所有权 let values = vec![1, 2, 3];
for v in values.into_iter() {
println!("{}", v)
}
// 下面的代码将报错,因为 values 的所有权在上面 `for` 循环中已经被转移走
// println!("{:?}",values);
let values = vec![1, 2, 3];
for v in values {
println!("{}", v)
}
// 下面的代码将报错,因为 values 的所有权在上面 `for` 循环中已经被转移走
// println!("{:?}", values); 借用 let values = vec![1, 2, 3];
for v in values.iter() {
println!("{}", v)
}
// 不会报错,因为 values_iter 只是借用了 values 中的元素
println!("{:?}", values);
let values = vec![1, 2, 3];
for v in &values {
println!("{}", v)
}
// 不会报错,因为 values_iter 只是借用了 values 中的元素
println!("{:?}", values); 可变借用 let mut values = vec![1, 2, 3];
// 对 values 中的元素进行可变借用
for v in values.iter_mut() {
*v = *v + 1;
}
// 输出[2, 3, 4]
println!("{:?}", values);
for v in &mut values {
*v = *v - 1;
}
// 输出[1, 2, 3]
println!("{:?}", values); |
Beta Was this translation helpful? Give feedback.
-
看了Iterator的源码,所有权和生命周期应该是编译器里的概念吧,实际在物理内存上并没有相应的变量,源码中用了各种底层的方法,像unsafe和unchecked。所以迭代器里面有很多概念不好理解,因为没有对应的底层实现,要死记硬背概念。下面简单举两个所有权和生命周期的例子(希望我的语言表述没问题)。 像数组的into_iter(self)方法,是标记了拿走数组所有权,实际上应该是每次调用next()时才具体的拿走每个元素的所有权,离开作用域才一个个元素去drop()。在for循环里,数组不能使用因为其所有权已经被拿走了,哪怕某些元素其实还没有被drop。 举例:如下代码无法编译,因为在for里面已经标记了数组整体的可变借用
|
Beta Was this translation helpful? Give feedback.
-
这两个bench mark test不是很严谨,其中产生随机数的代码,可能会导致计算结果的变动: fn rand_array(cnt: u32) -> Vec<f64> {
let mut rng = thread_rng();
(0..cnt).map(|_| rng.gen::<f64>()).collect()
}
#[bench]
fn bench_for(b: &mut Bencher) {
let samples = rand_array(LEN as u32);
b.iter(|| {
sum_for(&samples)
})
}
#[bench]
fn bench_iter(b: &mut Bencher) {
let samples = rand_array(LEN as u32);
b.iter(|| {
sum_iter(&samples)
})
} |
Beta Was this translation helpful? Give feedback.
-
习题在英文版:https://practice.course.rs/functional-programing/iterator.html |
Beta Was this translation helpful? Give feedback.
-
names.into_iter().zip(ages.into_iter()).collect(); |
Beta Was this translation helpful? Give feedback.
-
好家伙,生命周期、迭代器两个小节学了两天...这难度噶一下就上来了... 对于文章里面说的: 推荐大家边看边写,边验证,手动实现一下三种类型的迭代器,应该会比单纯的看要理解的深刻一些,比如像下面就是我“理解”之后,为的自定义类型实现的三个迭代器(为了学习,没有简洁实用Vec自带的迭代器,如果是项目考虑,肯定是直接用Vec的就可以了): // lib.rs
pub mod net_lib {
#[derive(Debug)]
pub struct NetState {
pub is_connected: bool,
pub link_address: Vec<String>,
}
impl NetState {
// 获取:不可变借用迭代器
pub fn iter(&self) -> NetIter {
self.into_iter()
}
// 获取:可变借用迭代器
pub fn iter_mut(&mut self) -> NetMutIter {
self.into_iter()
}
// 获取:消耗迭代器
// into_iter 方法使用 IntoIterator Trait 实现,因此可以实现消耗迭代器
// fn into_iter(self) -> IntoNetIter;
}
// ======================================= 消耗迭代器 =======================================
pub struct IntoNetIter {
pub remaining: Vec<String>,
}
// 实现迭代器 Trait
impl Iterator for IntoNetIter {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.remaining.pop()
}
}
// 实现 IntoIterator 接口,适配 for 语法糖
impl IntoIterator for NetState {
type Item = String;
type IntoIter = IntoNetIter;
// 此处 self 类型是 NetState,因此调用into_iter时会出现所有权转移(消耗掉上下文对象)
fn into_iter(self) -> Self::IntoIter {
IntoNetIter {
remaining: self.link_address.into_iter().rev().collect(),
}
}
}
// ======================================= 可变借用迭代器 =======================================
pub struct NetMutIter<'a> {
pub remaining: &'a mut [String],
}
// 实现迭代器 Trait
impl<'a> Iterator for NetMutIter<'a> {
type Item = &'a mut String;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining.is_empty() {
None
} else {
let all_slice = std::mem::take(&mut self.remaining);
let (first, rest) = all_slice.split_first_mut()?;
self.remaining = rest;
Some(first)
}
}
}
// 使用IntoIterator 接口,适配 for 语法糖
impl<'a> IntoIterator for &'a mut NetState {
type Item = &'a mut String;
type IntoIter = NetMutIter<'a>;
// 此处 self 类型是 &'a mut NetState,因此调用into_iter时不会出现所有权转移(不消耗掉上下文对象)
fn into_iter(self) -> Self::IntoIter {
NetMutIter {
remaining: &mut self.link_address[..],
}
}
}
// ======================================= 借用迭代器 =======================================
pub struct NetIter<'a> {
pub remaining: &'a [String],
}
// 实现迭代器
impl<'a> Iterator for NetIter<'a> {
type Item = &'a String;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining.is_empty() {
None
} else {
let all_slice = std::mem::take(&mut self.remaining);
let (first, rest) = all_slice.split_first()?;
self.remaining = rest;
Some(first)
}
}
}
// 实现IntoIterator接口,适配for语法糖
impl<'a> IntoIterator for &'a NetState {
type Item = &'a String;
type IntoIter = NetIter<'a>;
fn into_iter(self) -> Self::IntoIter {
NetIter {
remaining: &self.link_address[..],
}
}
}
}
// main.rs
use test_base_1::net_lib;
fn main() {
let mut connect_info = net_lib::NetState {
is_connected: true,
link_address: vec!["192.168.1.1".to_string(), "192.168.1.2".to_string()],
};
for addr in connect_info.iter() {
println!("不可变借用迭代 -> {addr}");
}
for addr in connect_info.iter_mut() {
*addr = format!("{addr} modified");
println!("可变借用迭代 -> {addr}");
}
println!("{connect_info:#?}");
for addr in connect_info.into_iter() {
println!("消耗迭代 -> {addr}");
}
// 编译错误,因为 connect_info 的所有权已经被消耗掉了
// println!("{connect_info:#?}");
} 加油兄弟萌,后面还有更难的 🤣🤣 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
advance/functional-programing/iterator
https://course.rs/advance/functional-programing/iterator.html
Beta Was this translation helpful? Give feedback.
All reactions