やっと見つけた。
成果物
参考
コードを読むとiter()
, iter_mut()
が実装されている。だが、標準モジュールでなく自作の構造体にみえる。これでmap()
, filter()
などを使えるのか? まずは、動作確認から。
動作確認
コードを入手してテストを実行する。
$ git clone https://github.com/Gankro/too-many-lists $ cd lists $ cargo test
コンパイルエラー……。
error[E0382]: use of moved value: `node` --> src/first.rs:36:22 | 35 | self.head = node.next; | --------- value moved here 36 | Some(node.elem) | ^^^^^^^^^ value used here after move | = note: move occurs because `node.next` has type `first::Link`, which does not implement the `Copy` trait error[E0382]: use of moved value: `node` --> src/second.rs:29:13 | 28 | self.head = node.next; | --------- value moved here 29 | node.elem | ^^^^^^^^^ value used here after move | = note: move occurs because `node.next` has type `std::option::Option<std::boxed::Box<second::Node<T>>>`, which does not implement the `Copy` trait error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0382`. error: Could not compile `lists`. warning: build failed, waiting for other jobs to finish... error[E0382]: use of moved value: `node` --> src/first.rs:36:22 | 35 | self.head = node.next; | --------- value moved here 36 | Some(node.elem) | ^^^^^^^^^ value used here after move | = note: move occurs because `node.next` has type `first::Link`, which does not implement the `Copy` trait error[E0382]: use of moved value: `node` --> src/second.rs:29:13 | 28 | self.head = node.next; | --------- value moved here 29 | node.elem | ^^^^^^^^^ value used here after move | = note: move occurs because `node.next` has type `std::option::Option<std::boxed::Box<second::Node<T>>>`, which does not implement the `Copy` trait error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0382`. error: Could not compile `lists`. To learn more, run the command again with --verbose.
エラーはfirst.rs
, second.rs
の2ファイルのみ。そこでコードを以下のように修正した。
lib.rs
//pub mod first; //pub mod second; pub mod third; pub mod fourth; pub mod fifth; pub mod silly1;
これでテストは通った。たぶんドキュメントの1章, 2章に対応したコードなのだろう。まだ途中であってエラーを含んでいたコードだったのかな?
$ cargo test ... running 10 tests test fifth::test::basics ... ok test fifth::test::iter ... ok test fifth::test::iter_mut ... ok test fourth::test::basics ... ok test fourth::test::into_iter ... ok test silly1::test::walk_aboot ... ok test fourth::test::peek ... ok test third::test::basics ... ok test third::test::iter ... ok test fifth::test::into_iter ... ok test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ...
map
やfilter
が使えるか確認
最終章のコードが完成版だろうと予想し、それにテストコードを追加してみた。
map
fifth.rs
#[test] fn iter_mut_2() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let expecteds = vec![10,20,30]; for (i, value) in list.iter_mut().map(|elem| *elem * 10).enumerate() { assert_eq!(value, expecteds[i]) } }
map
で新たなイテレータを生成できたことを確認。
filter
let mut list = List::new(); list.push(1); list.push(2); list.push(3); let expecteds = vec![1,2,3]; for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter_mut().filter(|elem| **elem % 2 == 0).enumerate() { assert_eq!(*value, 2) }
filter
で偶数のみ抽出できたことを確認。
mutable
let mut expecteds = vec![10,20,30]; for (i, value) in list.iter_mut().enumerate() { *value *= 10; } for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) }
値の代入ができた(可変性がある)ことを確認。
最終コード
$ cargo new list_iter --lib
lib.rs
use std::ptr; pub struct List<T> { head: Link<T>, tail: *mut Node<T>, } type Link<T> = Option<Box<Node<T>>>; struct Node<T> { elem: T, next: Link<T>, } impl<T> List<T> { pub fn new() -> Self { List { head: None, tail: ptr::null_mut() } } pub fn push(&mut self, elem: T) { let mut new_tail = Box::new(Node { elem: elem, next: None, }); let raw_tail: *mut _ = &mut *new_tail; if !self.tail.is_null() { unsafe { (*self.tail).next = Some(new_tail); } } else { self.head = Some(new_tail); } self.tail = raw_tail; } pub fn pop(&mut self) -> Option<T> { self.head.take().map(|head| { let head = *head; self.head = head.next; if self.head.is_none() { self.tail = ptr::null_mut(); } head.elem }) } pub fn peek(&self) -> Option<&T> { self.head.as_ref().map(|node| { &node.elem }) } pub fn peek_mut(&mut self) -> Option<&mut T> { self.head.as_mut().map(|node| { &mut node.elem }) } pub fn into_iter(self) -> IntoIter<T> { IntoIter(self) } pub fn iter(&self) -> Iter<'_, T> { Iter { next: self.head.as_ref().map(|node| &**node) } } pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { next: self.head.as_mut().map(|node| &mut **node) } } } pub struct IntoIter<T>(List<T>); pub struct Iter<'a, T> { next: Option<&'a Node<T>>, } pub struct IterMut<'a, T> { next: Option<&'a mut Node<T>>, } impl<T> Drop for List<T> { fn drop(&mut self) { let mut cur_link = self.head.take(); while let Some(mut boxed_node) = cur_link { cur_link = boxed_node.next.take(); } } } impl<T> Iterator for IntoIter<T> { type Item = T; fn next(&mut self) -> Option<Self::Item> { self.0.pop() } } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<Self::Item> { self.next.map(|node| { self.next = node.next.as_ref().map(|node| &**node); &node.elem }) } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option<Self::Item> { self.next.take().map(|node| { self.next = node.next.as_mut().map(|node| &mut **node); &mut node.elem }) } } #[cfg(test)] mod test { use super::List; #[test] fn basics() { let mut list = List::new(); // Check empty list behaves right assert_eq!(list.pop(), None); // Populate list list.push(1); list.push(2); list.push(3); // Check normal removal assert_eq!(list.pop(), Some(1)); assert_eq!(list.pop(), Some(2)); // Push some more just to make sure nothing's corrupted list.push(4); list.push(5); // Check normal removal assert_eq!(list.pop(), Some(3)); assert_eq!(list.pop(), Some(4)); // Check exhaustion assert_eq!(list.pop(), Some(5)); assert_eq!(list.pop(), None); // Check the exhaustion case fixed the pointer right list.push(6); list.push(7); // Check normal removal assert_eq!(list.pop(), Some(6)); assert_eq!(list.pop(), Some(7)); assert_eq!(list.pop(), None); } #[test] fn into_iter() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let mut iter = list.into_iter(); assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), Some(2)); assert_eq!(iter.next(), Some(3)); assert_eq!(iter.next(), None); } #[test] fn iter() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let mut iter = list.iter(); assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), Some(&3)); assert_eq!(iter.next(), None); } #[test] fn iter_mut() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let mut iter = list.iter_mut(); assert_eq!(iter.next(), Some(&mut 1)); assert_eq!(iter.next(), Some(&mut 2)); assert_eq!(iter.next(), Some(&mut 3)); assert_eq!(iter.next(), None); } #[test] fn iter_2() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let expecteds = vec![1,2,3]; for (i, value) in list.iter().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter().enumerate() { assert_eq!(*value, expecteds[i]) } let expecteds = vec![10,20,30]; for (i, value) in list.iter().map(|elem| *elem * 10).enumerate() { assert_eq!(value, expecteds[i]) } for (i, value) in list.iter_mut().filter(|elem| **elem % 2 == 0).enumerate() { assert_eq!(*value, 2); } } #[test] fn iter_mut_3() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let expecteds = vec![10,20,30]; for (i, value) in list.iter_mut().map(|elem| *elem * 10).enumerate() { assert_eq!(value, expecteds[i]) } let expecteds = vec![1,2,3]; for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter_mut().filter(|elem| **elem % 2 == 0).enumerate() { assert_eq!(*value, 2); } let mut expecteds = vec![10,20,30]; for (i, value) in list.iter_mut().enumerate() { *value *= 10; } for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } } }
$ cargo test ... running 6 tests test test::basics ... ok test test::into_iter ... ok test test::iter ... ok test test::iter_mut ... ok test test::iter_2 ... ok test test::iter_mut_3 ... ok test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ...
コードを読む
List
とNode
の構造体。
pub struct List<T> { head: Link<T>, tail: *mut Node<T>, } type Link<T> = Option<Box<Node<T>>>; struct Node<T> { elem: T, next: Link<T>, }
iter()
メソッド等の実装。
impl<T> List<T> { ... pub fn into_iter(self) -> IntoIter<T> { IntoIter(self) } pub fn iter(&self) -> Iter<'_, T> { Iter { next: self.head.as_ref().map(|node| &**node) } } pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { next: self.head.as_mut().map(|node| &mut **node) } }
self.head.as_ref().map
?
iter()
はNode
インスタンスへの不変参照をもった構造体Iter
を返す。
そのうちself.head.as_ref().map
の部分がよくわからない。self.head
はOption<Box<Node<T>>>
であり、その参照を取得すべくas_ref()
しているのはわかる。だが、Box
やNode
はmap
メソッドなど持っていないと思うのだが。
一体、いつNode
にmap
メソッドが実装されたのか? そのコードはどこ?
pub struct IntoIter<T>(List<T>); pub struct Iter<'a, T> { next: Option<&'a Node<T>>, } pub struct IterMut<'a, T> { next: Option<&'a mut Node<T>>, } impl<T> Drop for List<T> { fn drop(&mut self) { let mut cur_link = self.head.take(); while let Some(mut boxed_node) = cur_link { cur_link = boxed_node.next.take(); } } } impl<T> Iterator for IntoIter<T> { type Item = T; fn next(&mut self) -> Option<Self::Item> { self.0.pop() } } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<Self::Item> { self.next.map(|node| { self.next = node.next.as_ref().map(|node| &**node); &node.elem }) } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option<Self::Item> { self.next.take().map(|node| { self.next = node.next.as_mut().map(|node| &mut **node); &mut node.elem }) } }
Iter
, IterMut
は自前の構造体らしい。
pub struct IntoIter<T>(List<T>); pub struct Iter<'a, T> { next: Option<&'a Node<T>>, } pub struct IterMut<'a, T> { next: Option<&'a mut Node<T>>, }
map
実装箇所特定のため、それに無関係と思われるコードをコメントアウトする。以下、コンパイルできた。
use std::ptr; pub struct List<T> { head: Link<T>, tail: *mut Node<T>, } type Link<T> = Option<Box<Node<T>>>; struct Node<T> { elem: T, next: Link<T>, } impl<T> List<T> { pub fn new() -> Self { List { head: None, tail: ptr::null_mut() } } pub fn push(&mut self, elem: T) { let mut new_tail = Box::new(Node { elem: elem, next: None, }); let raw_tail: *mut _ = &mut *new_tail; if !self.tail.is_null() { unsafe { (*self.tail).next = Some(new_tail); } } else { self.head = Some(new_tail); } self.tail = raw_tail; } pub fn iter(&self) -> Iter<'_, T> { Iter { next: self.head.as_ref().map(|node| &**node) } } pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { next: self.head.as_mut().map(|node| &mut **node) } } } pub struct Iter<'a, T> { next: Option<&'a Node<T>>, } pub struct IterMut<'a, T> { next: Option<&'a mut Node<T>>, } impl<T> Drop for List<T> { fn drop(&mut self) { let mut cur_link = self.head.take(); while let Some(mut boxed_node) = cur_link { cur_link = boxed_node.next.take(); } } } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<Self::Item> { self.next.map(|node| { self.next = node.next.as_ref().map(|node| &**node); &node.elem }) } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option<Self::Item> { self.next.take().map(|node| { self.next = node.next.as_mut().map(|node| &mut **node); &mut node.elem }) } }
#[cfg(test)] mod test { use super::List; #[test] fn iter() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let mut iter = list.iter(); assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), Some(&3)); assert_eq!(iter.next(), None); } #[test] fn iter_mut() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let mut iter = list.iter_mut(); assert_eq!(iter.next(), Some(&mut 1)); assert_eq!(iter.next(), Some(&mut 2)); assert_eq!(iter.next(), Some(&mut 3)); assert_eq!(iter.next(), None); } #[test] fn iter_2() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let expecteds = vec![1,2,3]; for (i, value) in list.iter().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter().enumerate() { assert_eq!(*value, expecteds[i]) } let expecteds = vec![10,20,30]; for (i, value) in list.iter().map(|elem| *elem * 10).enumerate() { assert_eq!(value, expecteds[i]) } for (i, value) in list.iter_mut().filter(|elem| **elem % 2 == 0).enumerate() { assert_eq!(*value, 2); } } #[test] fn iter_mut_3() { let mut list = List::new(); list.push(1); list.push(2); list.push(3); let expecteds = vec![10,20,30]; for (i, value) in list.iter_mut().map(|elem| *elem * 10).enumerate() { assert_eq!(value, expecteds[i]) } let expecteds = vec![1,2,3]; for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } for (i, value) in list.iter_mut().filter(|elem| **elem % 2 == 0).enumerate() { assert_eq!(*value, 2); } let mut expecteds = vec![10,20,30]; for (i, value) in list.iter_mut().enumerate() { *value *= 10; } for (i, value) in list.iter_mut().enumerate() { assert_eq!(*value, expecteds[i]) } } }
- Option.mapメソッド
もしやOption
のメソッドだったのか? Option.mapはOption::Some(T)
のT
インスタンスを別の型にした値として新規生成し、返却するメソッドと思われる。
pub fn iter(&self) -> Iter<'_, T> { Iter { next: self.head.as_ref().map(|node| &**node) } } pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { next: self.head.as_mut().map(|node| &mut **node) } }
上記コードのmap
はOption<Box<Node<T>>>
を&Option<Node<T>>
に変換ている。
self.head
はOption<Box<Node<T>>>
。Option.as_ref()
で不変参照にしつつOption.map()
で別型を生成する。型はBox
を参照外しして&
を付与する。つまり&Option<Node<T>>
型。最後にIter
構造体にくるんで返す。
でもlist.iter().map(|elem| *elem * 10).enumerate()
は? enumerate()
メソッドはOption
型に実装されていない。でも、以下コードは動く。なぜ?
for (i, value) in list.iter().map(|elem| *elem * 10).enumerate() { assert_eq!(value, expecteds[i]) }
さすがにenumerate
はイテレータ型でないと実装されていないはず。いつからイテレータ型になっていた? そして、どこでそれを実装している?
impl<'a, T> Iterator for Iter<'a, T>
もしや、以下だろうか。
impl<'a, T> Iterator for Iter<'a, T> { impl<'a, T> Iterator for IterMut<'a, T> {
Iterator
はstd::iter::Iterator
のことである(標準モジュールであって自作でない)- 自作の
Iter
,IterMut
にstd::iter::Iterator
を実装する - 2にて、
Iter
,IterMut
を返すメソッドiter()
,iter_mut()
はイテレータとなる list.iter()
はすでにイテレータ型であり、enumerate()
,map()
,filter()
などが使える
という解釈で合っているかな?
それだと、std::iter::Iterator
トレイトを実装すればいいことになる。だが、これまでは要素が消費されてしまう実装しかできなかった。今回、消費されず参照を返す実装ができていた。違いはどこにあるのか?
おそらく以下コードの&'a
, &'a mut
がポイント。そのためだけにIter
, IterMut
構造体をわざわざ新設し、それぞれに以下のようなトレイト実装をしている。これにてiter()
, iter_mut()
は消費しない参照を返すイテレータになれたのだろう。
impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<Self::Item> { self.next.map(|node| { self.next = node.next.as_ref().map(|node| &**node); &node.elem }) } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option<Self::Item> { self.next.take().map(|node| { self.next = node.next.as_mut().map(|node| &mut **node); &mut node.elem }) } }
つまり、以下のような3種類の型に、それぞれstd::iter::Iterator
トレイトのnext
メソッドをオーバーライドせねばならない。
型 | type Item |
---|---|
値 | T |
不変参照 | &'a T |
可変参照 | &'a mut T |
ほぼ重複するコードを大量に書くハメになる。DRYに書けないとかダサすぎる。
消費されない理由
イテレータの要素が消費されない理由。Iter
, IterMut
構造体インスタンスはList
が所有権をもつNode
インスタンスの参照変数をもつだけ。だからIter
はList
やNode
からそれらの所有権を奪わない。Iter
は単に参照変数をもった構造体として新規生成される。
もっとも、Iter
, IterMut
インスタンスは所有権をムーブしているが、それらは毎回生成して使い捨てればいい。
という解釈で合っていると思う。
Iter.next()
最初はList.head
。その参照をとる。List.head
はNode
インスタンスを指す。Node
がもつnext
の参照を、Iter.next
にセットする。これにて次回は次のノードに対して実行する。最後にNode.elem
の参照を返す。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12(1)-release
- rustc 1.34.2 (6c2484dc3 2019-05-13)
- cargo 1.34.0 (6789d8a0a 2019-04-01)
$ uname -a Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux
前回まで
- Rust学習まとめ(ドキュメント)
- Rust自習(じゃんけんゲーム1)
- Rust自習(双方向リスト1)
- Rust自習(単方向リスト1)
- Rust自習(単方向リスト2)
- Rust自習(単方向リスト3)
- Rust自習(単方向リスト4)
- Rust自習(単方向リスト5)
- Rust自習(単方向リスト6)
- Rust自習(単方向リスト7)
- Rust自習(リストのインタフェースを考える)
- Rust自習(連結リスト1)
- Rust自習(連結リスト2)
- Rust自習(連結リスト3)
- Rust自習(連結リスト4)
- Rust自習(連結リストの取得系インタフェース考察)
- Rust自習(連結リスト5)
- Rust自習(連結リストの取得系インタフェース考察2)
- Rust自習(連結リスト6)
- Rust自習(連結リスト7)
- Rust自習(連結リスト8)
- Rust自習(連結リスト9)
- Rust自習(変数名でイテレートする方法)