网站广告位怎么做,丰都网站建设联系电话,个人与企业签订网站开发合同,怎么套模板做网站Iterator即迭代器#xff0c;它可以用于对数据结构进行迭代。被迭代的数据结构是可迭代的(iterable)#xff0c;所谓的可迭代就是这个数据结构有返回迭代器的方法#xff0c;由于Rust的所有权机制#xff0c;对一个数据结构的迭代器#xff0c;有三种#xff1a;
拿走数…Iterator即迭代器它可以用于对数据结构进行迭代。被迭代的数据结构是可迭代的(iterable)所谓的可迭代就是这个数据结构有返回迭代器的方法由于Rust的所有权机制对一个数据结构的迭代器有三种
拿走数据结构的所有权的迭代器在数据结构的方法上体现为into_iter(self)。在Rust中into方法通常都是拿走所有权的而且方法的入参self也表明了会拿走所有权不会拿走所有权的是self、mut self这种入参。不拿走数据结构的所有权只读取数据结构内容的迭代器在数据结构的方法上体现为iter(self)。self表明了只是只读借用。不拿走数据结构的所有权但是可以读写数据结构内容的迭代器在数据结构的方法上体现为iter_mut(mut self)。
每调用一次数据结构的迭代器方法就会返回一个迭代器拿走数据结构所有权的迭代器方法只能调用一次迭代器迭代完了就不能继续使用了。
迭代器在Rust中是一个trait:
pub trait Iterator {/// The type of the elements being iterated over./// 迭代器迭代的元素类型#[stable(feature rust1, since 1.0.0)]type Item;/// Advances(向前移动) the iterator and returns the next value.////// Returns [None] when iteration is finished. Individual iterator/// implementations may choose to resume iteration, and so calling next()/// again may or may not eventually start returning [Some(Item)] again at some/// point./// 迭代器取下一个元素的方法如果没有下一个元素会返回None/// 请注意next方法的入参是mut self也就是入参是可变的迭代器为什么可变因为迭代器内部通常都有/// 记录迭代进度的变量比如数组下标这种随着迭代的进行变量会自增所以需要改变迭代器的状态用可变借用fn next(mut self) - OptionSelf::Item;/// 省略其它内容
}你可以为你的数据结构实现Iterator trait使得它可迭代。我们通常在for循环中使用迭代器。Rust标准库中的集合基本上都提供了返回迭代器的方法。比如我们最常用的Vec
fn main() {// 下面是只读迭代器的使用let students vec![张三.to_string(),李四.to_string(),韩老二.to_string()];for student in students{println!(students写法:{},student);}// Vec的iter()方法返回的是只读迭代器for student in students.iter(){println!(iter()方法调用写法:{},student);}let mut ugly_girls vec![韩老二.to_string(),叶慧三.to_string()];// for循环中的mut ugly_girls写法等同于ugly_girls.iter_mut()for girl in mut ugly_girls{girl.push_str(--really );}// iter_mut()方法返回的是读写迭代器可以对被迭代的元素进行修改for girl in ugly_girls.iter_mut(){girl.push_str(ugly);}println!({:?},ugly_girls);let ugly_boys vec![吴亦.to_string(),肖障.to_string()];// for ugly_boy in ugly_boys等同于for ugly_boy in ugly_boys.into_iterfor ugly_boy in ugly_boys {println!({},ugly_boy);}// 这儿不能再访问ugly_boys了因为它的所有权在for循环的时候就被转移到迭代器中了
}执行上述的代码后输出:
students写法:张三
students写法:李四
students写法:韩老二
iter()方法调用写法:张三
iter()方法调用写法:李四
iter()方法调用写法:韩老二
[韩老二--really ugly, 叶慧三--really ugly]
吴亦
肖障好了让我们来自己搞一个数据结构然后为它实现三个迭代器方法加深理解。
假设我们有一个struct:
#[derive(Debug)]
pub struct SongList {// 歌单中歌曲列表pub songs: VecString,// 歌单创建时间pub create_time: SystemTime,
}表示歌单的数据结构如果我们想要在for循环中去迭代歌单内容我们当然可以直接通过SongList的songs字段进行迭代但是这个是利用了Vec为我们实现好的迭代器如果我们不暴露SongList内部的结构把SongList当成一个黑盒去遍历我们需要为它实现几个迭代器方法每个方法返回一个迭代器从而可以在for循环中通过迭代器来迭代SongList。
我们需要三个自定义的structIter、IterMut、IntoIter分别表示SongList的三种迭代器然后需要SongList提供三个方法分别返回三种迭代器
impl SongList {fn iter(self) - Iter {Iter::new(self)}fn iter_mut(mut self) - IterMut {IterMut::new(self)}fn into_iter(self)-IntoIter{IntoIter::new(self)}
}实现只读迭代器
// 只读迭代器会用到引用所以struct要带生命周期范型这儿遵循Rust习惯用a表示生命周期参数
pub struct Itera {// 迭代器本身不拥有被迭代的数据而是引用被迭代的数据所以需要定义引用有人的地方就有江湖同样有引用的地方就有生命周期apub song_list: a SongList,// 记录迭代进度的变量pub index: usize,
}impla Itera {// 传入SongList引用就可以创建迭代器Iterfn new(song_list: a SongList) - Iter {Iter {song_list,index: 0,}}
}// 为Iter实现Iterator trait从而让它变成真正的迭代器
impla Iterator for Itera {type Item a String;fn next(mut self) - OptionSelf::Item {if self.index self.song_list.songs.len() {let result Some(self.song_list.songs[self.index]);self.index 1;result} else {None}}
}// 为了让我们可以在for循环中通过song_list来替代song_list.iter()需要为SongList实现IntoIterator
// 参考https://doc.rust-lang.org/std/iter/index.html中提到的内容
// If a collection type C provides iter(), it usually also implements IntoIterator for C,
// with an implementation that just calls iter(). Likewise, a collection C that provides iter_mut()
// generally implements IntoIterator for mut C by delegating to iter_mut(). This enables a convenient shorthand:
//
// let mut values vec![41];
// for x in mut values { // same as values.iter_mut()
// *x 1;
// }
// for x in values { // same as values.iter()
// assert_eq!(*x, 42);
// }
// assert_eq!(values.len(), 1);
impla IntoIterator for a SongList {// 我们的SongList中被迭代的songs是VecString所以这儿迭代的Item就是Stringtype Item a String;type IntoIter Itera;fn into_iter(self) - Self::IntoIter {self.iter()}
}impl SongList {fn iter(self) - Iter {Iter::new(self)}
}fn main() {let song_list SongList {songs: vec![做个真的我.to_string(),刀剑如梦.to_string(),难念的经.to_string(),任逍遥.to_string(),],create_time: SystemTime::now(),};for song in song_list.iter() {println!({}, song);}for song in song_list {println!({}, song);}println!(song_list:{:#?}, song_list);
}实现可修改迭代器
// 读写迭代器
pub struct IterMuta {// 要持有被迭代数据结构的可变应用song_list: a mut SongList,index: usize,
}impla IterMuta {// 将mut SongList变成IterMut的方法fn new(song_list: a mut SongList) - IterMut {IterMut {song_list,index: 0,}}
}// 为IterMut实现Iterator trait让它成为一个真正的迭代器
impla Iterator for IterMuta {type Item a mut String;fn next( mut self) - OptionSelf::Item {if self.index self.song_list.songs.len() {let ptr self.song_list.songs.as_mut_ptr();let result Some(unsafe{mut *ptr.add(self.index)});// 上面两行不能用下面这一行实现// 否则会报错error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements// 参考https://stackoverflow.com/questions/62361624/lifetime-parameter-problem-in-custom-iterator-over-mutable-references// let result Some(mut self.song_list.songs[self.index]);self.index 1;result} else {None}}
}
// 为了让我们可以在for循环中通过mut song_list来替代song_list.iter_mut()需要为mut SongList实现IntoIterator
impla IntoIterator for a mut SongList {type Item a mut String;type IntoIter IterMuta;fn into_iter(self) - Self::IntoIter {self.iter_mut()}
}impl SongList {fn iter_mut(mut self) - IterMut {IterMut::new(self)}
}fn main() {let mut zhangsan_song_list SongList {songs: vec![笑脸盈盈.to_string(), 我是一只鱼.to_string()],create_time: SystemTime::now(),};for song in mut zhangsan_song_list{song.push_str(-真的);}for song in zhangsan_song_list.iter_mut() {song.push_str(-好好听啊);}println!(zhagnsan_song_list:{:#?}, zhangsan_song_list);
}实现可以会拿走所有权的迭代器
// 定义一个会拿走所有权的迭代器struct
pub struct IntoIter{song_list:SongList// 不用index了因为拿走所有权的话从songs中拿走一个就少一个不用再记录迭代进度了迭代过的都被从Vec中移除了
}impl IntoIter {// 将SongList直接消耗掉变成IntoIter传入的song_list变量的所有权就这样被转移到了迭代器中fn new(song_list:SongList)-Self{IntoIter{song_list}}
}// 为IntoIter实现Iterator trait让它成为一个真正的迭代器
impl Iterator for IntoIter {type Item String;fn next(mut self) - OptionSelf::Item {// 从Vec中pop出的元素就没了所以不需要我们额外定义index来记录迭代进度了self.song_list.songs.pop()}
}// 为了让我们可以在for循环中通过for item in song_list来替代for item in song_list.into_iter()需要为SongList实现IntoIterator
impl IntoIterator for SongList {type Item String;type IntoIter IntoIter;// 直接消耗掉SongList类型变量将其所有权转移到迭代器中fn into_iter(self) - Self::IntoIter {IntoIter::new(self)}
}impl SongList {fn into_iter(self)-IntoIter{IntoIter::new(self)}
}fn main() {let lisi_song_list SongList{songs:vec![天涯.to_string(),死不了.to_string()],create_time:SystemTime::now()};//或者直接写成 for song in lisi_song_list{for song in lisi_song_list.into_iter(){println!({},song);}
}完整代码
use std::iter::Iterator;
use std::time::SystemTime;#[derive(Debug)]
pub struct SongList {// 歌单中歌曲列表pub songs: VecString,// 歌单创建时间pub create_time: SystemTime,
}// 只读迭代器会用到引用所以struct要带生命周期范型这儿遵循Rust习惯用a表示生命周期参数
pub struct Itera {// 迭代器本身不拥有被迭代的数据而是引用被迭代的数据所以需要定义引用有人的地方就有江湖同样有引用的地方就有生命周期apub song_list: a SongList,// 记录迭代进度的变量pub index: usize,
}impla Itera {// 传入SongList引用就可以创建迭代器Iterfn new(song_list: a SongList) - Iter {Iter {song_list,index: 0,}}
}// 为Iter实现Iterator trait从而让它变成真正的迭代器
impla Iterator for Itera {type Item a String;fn next(mut self) - OptionSelf::Item {if self.index self.song_list.songs.len() {let result Some(self.song_list.songs[self.index]);self.index 1;result} else {None}}
}// 为了让我们可以在for循环中通过song_list来替代song_list.iter()需要为SongList实现IntoIterator
// 参考https://doc.rust-lang.org/std/iter/index.html中提到的内容
// If a collection type C provides iter(), it usually also implements IntoIterator for C,
// with an implementation that just calls iter(). Likewise, a collection C that provides iter_mut()
// generally implements IntoIterator for mut C by delegating to iter_mut(). This enables a convenient shorthand:
//
// let mut values vec![41];
// for x in mut values { // same as values.iter_mut()
// *x 1;
// }
// for x in values { // same as values.iter()
// assert_eq!(*x, 42);
// }
// assert_eq!(values.len(), 1);
impla IntoIterator for a SongList {// 我们的SongList中被迭代的songs是VecString所以这儿迭代的Item就是Stringtype Item a String;type IntoIter Itera;fn into_iter(self) - Self::IntoIter {self.iter()}
}// 读写迭代器
pub struct IterMuta {// 要持有被迭代数据结构的可变应用song_list: a mut SongList,index: usize,
}impla IterMuta {// 将mut SongList变成IterMut的方法fn new(song_list: a mut SongList) - IterMut {IterMut {song_list,index: 0,}}
}// 为IterMut实现Iterator trait让它成为一个真正的迭代器
impla Iterator for IterMuta {type Item a mut String;fn next( mut self) - OptionSelf::Item {if self.index self.song_list.songs.len() {let ptr self.song_list.songs.as_mut_ptr();let result Some(unsafe{mut *ptr.add(self.index)});// 上面两行不能用下面这一行实现// 否则会报错error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements// 参考https://stackoverflow.com/questions/62361624/lifetime-parameter-problem-in-custom-iterator-over-mutable-references// let result Some(mut self.song_list.songs[self.index]);self.index 1;result} else {None}}
}
// 为了让我们可以在for循环中通过mut song_list来替代song_list.iter_mut()需要为mut SongList实现IntoIterator
impla IntoIterator for a mut SongList {type Item a mut String;type IntoIter IterMuta;fn into_iter(self) - Self::IntoIter {self.iter_mut()}
}// 定义一个会拿走所有权的迭代器struct
pub struct IntoIter{song_list:SongList// 不用index了因为拿走所有权的话从songs中拿走一个就少一个不用再记录迭代进度了迭代过的都被从Vec中移除了
}impl IntoIter {// 将SongList直接消耗掉变成IntoIter传入的song_list变量的所有权就这样被转移到了迭代器中fn new(song_list:SongList)-Self{IntoIter{song_list}}
}// 为IntoIter实现Iterator trait让它成为一个真正的迭代器
impl Iterator for IntoIter {type Item String;fn next(mut self) - OptionSelf::Item {// 从Vec中pop出的元素就没了所以不需要我们额外定义index来记录迭代进度了self.song_list.songs.pop()}
}// 为了让我们可以在for循环中通过for item in song_list来替代for item in song_list.into_iter()需要为SongList实现IntoIterator
impl IntoIterator for SongList {type Item String;type IntoIter IntoIter;// 直接消耗掉SongList类型变量将其所有权转移到迭代器中fn into_iter(self) - Self::IntoIter {IntoIter::new(self)}
}impl SongList {fn iter(self) - Iter {Iter::new(self)}fn iter_mut(mut self) - IterMut {IterMut::new(self)}fn into_iter(self)-IntoIter{IntoIter::new(self)}
}fn main() {let song_list SongList {songs: vec![做个真的我.to_string(),刀剑如梦.to_string(),难念的经.to_string(),任逍遥.to_string(),],create_time: SystemTime::now(),};for song in song_list.iter() {println!({}, song);}for song in song_list {println!({}, song);}println!(song_list:{:#?}, song_list);let mut zhangsan_song_list SongList {songs: vec![笑脸盈盈.to_string(), 我是一只鱼.to_string()],create_time: SystemTime::now(),};for song in mut zhangsan_song_list{song.push_str(-真的);}for song in zhangsan_song_list.iter_mut() {song.push_str(-好好听啊);}println!(zhagnsan_song_list:{:#?}, zhangsan_song_list);let lisi_song_list SongList{songs:vec![天涯.to_string(),死不了.to_string()],create_time:SystemTime::now()};//或者直接写成 for song in lisi_song_list{for song in lisi_song_list.into_iter(){println!({},song);}
}
运行的控制台输出
做个真的我
刀剑如梦
难念的经
任逍遥
做个真的我
刀剑如梦
难念的经
任逍遥
song_list:SongList {songs: [做个真的我,刀剑如梦,难念的经,任逍遥,],create_time: SystemTime {tv_sec: 1690101338,tv_nsec: 120053000,},
}
zhagnsan_song_list:SongList {songs: [笑脸盈盈-真的-好好听啊,我是一只鱼-真的-好好听啊,],create_time: SystemTime {tv_sec: 1690101338,tv_nsec: 120146000,},
}
死不了
天涯