Rust part27 (406レス)
1-

68
(1): 2024/12/07(土)00:37 ID:MlZHBv1+(1/5) AAS
Vecなどを作れて逆順にもできるイテレータとは性質が異なる
異なるものを、どっちも同じだと頑なに主張し続ける必要はない気がする
69
(1): 2024/12/07(土)02:06 ID:TKfUhpHo(1/3) AAS
67は一般的なイテレータの概念じゃなくstd::iter::Iteratorの話
このtraitを実装すると例えばIterator::max()も自動的に使えるようになるけど
この実装はSelf::Itemの暫定の最大値を保持しながら次のnextを呼ぶ必要がある
前の値を解放しないと次のnextを使えない状態だと
std::iter::Iteratorが使用者側に保証してる条件を満たせないし
安全なコードの範囲でimpl Iteratorのコンパイルも通せない

自前のIteratorトレイトを用意してもいいけど
それだとstd::iter::Iteratorが要求される処理には使えなくなる
70
(1): 2024/12/07(土)08:46 ID:4WGAo47f(1/7) AAS
>>68
Vecを作れるのも逆順も全て別の話
それぞれ別の要件を備えていないと一般的なイテレータではどちらも不可能
例えばイテレータ「1..」はVecを作れない&逆順に呼ぶのも無理
std::iter::repeat(1)はVecを作れないがDoubleEndedIteratorを実装しているのでメソッドrev()が使えて逆順に呼べる!
自己可変参照を返す>>65のMyIterMutはスライス&mut [T]を内部に持っているため逆順呼び出しrev()メソッドの実装が可能
71: 2024/12/07(土)09:01 ID:4WGAo47f(2/7) AAS
>>69
そのmax()は自動的に全てのイテレータに使えるわけではない
Self::Itemがstd::cmp::Ordを実装している時のみ使える
前の値を保持したままにできるか否かの性質についてもmarker traitを用意することで同じ枠組みに組み込めた可能性がある
それを出来ていないのがstd::iter::Iteratorの欠陥なので他を併用するのがRustでは当たり前になっている
72: 2024/12/07(土)09:28 ID:4WGAo47f(3/7) AAS
イテレータの前の値を保持できるか否かのどちらが優れているかといえば
より効率的な機能を提供できる点で「前の値を保持できない」方が優れた機能を提供できる
例えばstd::io::BufReadのlines()を考えてみよう
毎回新たなStringを返してくるので前の値を保持できる仕様となっている
しかしlines()の利用で前の値なんて不要なことも多いからその観点からは無駄な仕様ともいえる
一方で「前の値を保持できない」性質にも対応出来ていたとしたら同じStringを使い回すことが出来て明らかに効率が良い
このような例は多数あり自己参照返しイテレータが別途必要とされて使われている理由である
73
(1): 2024/12/07(土)12:31 ID:MlZHBv1+(2/5) AAS
>>70
長さが有限でも実行時にメモリが足りなければVecもreverseもないけど
「実行時に」という要件は備えなくて良いというルールがあるんだよね?
74
(1): 2024/12/07(土)12:55 ID:TKfUhpHo(2/3) AAS
61(初心者)が実現できないimpl Iteratorで詰まってるんだから
できない理由を分かってもらうのが優先でしょ
イテレータの優劣とか代替案はその後でいい
75: 2024/12/07(土)13:24 ID:4WGAo47f(4/7) AAS
>>73
rev()メソッドのtrait DoubleEndedIteratorはゼロコスト抽象化
逆順に並べ替えることはしないのでそのためのメモリは必要ない
既にある任意の構造を後ろからたどる、あるいは、後ろから計算するだけ
76
(1): 2024/12/07(土)13:35 ID:4WGAo47f(5/7) AAS
>>74
それならば別の条件が必要となるIterator::max()を事例に出すのはよろしくないかな
説明するためには単純にこれだけでいいよ
let first = iter.next();
let second = iter.next();
println!("{first:?} {second:?}");
77
(1): 2024/12/07(土)14:11 ID:TKfUhpHo(3/3) AAS
>>76
next2回呼ぶだけだとstd::iter::Iteratorと関係なくなるだろ
自分がそういう使い方をしなければ問題ないってなるだけ

maxはstd::iter::Iteratorの実装に求められる条件の分かりやすい例として挙げた
別の条件まで気にするならmax_byでもいいけどそれはそれで初心者には余計なノイズが増える
78
(1): 2024/12/07(土)14:52 ID:MlZHBv1+(3/5) AAS
コピーもcloneもできないデータの存在自体がノイズだね
本当はcloneできるんだけどゼロコストではできないとか言ってるのもノイズだ
79: 2024/12/07(土)15:42 ID:YxUwNEYs(1) AAS
結局>>53は何がしたかったのか
80: 2024/12/07(土)16:58 ID:ikP3bVWr(1) AAS
>>67
stdのIterator::nextの&mut selfのライフタイムはnextメソッドを抜けるところまで
(次のnextが呼ばれるまで生きてない)

つまりstdのIteratorでは&mut selfのライフタイムに依存するような参照を返すことはできないということ
そういう参照を返したいならlending iterator
逆に言えば&mut selfのライフタイムに依存しない参照であればstdのIteratorでも返せるということ
81: 2024/12/07(土)17:27 ID:4WGAo47f(6/7) AAS
>>77
max_byも同じ
Ord実装型そのものかOrd実装型に変換してOrd::cmp()できる時のみ利用できる
それらを持ち出さなくてもSelf::Itemの条件なくcollect()すなわち収納型へのFromIteratorが適用される
つまりfirst要素とsecond要素が同時に存在することになると矛盾の説明で十分となる
そのため自己参照を返すイテレータはstd::iter::Iteratorがカバーする範囲になく別途必要となる話をしてきた
82: 2024/12/07(土)17:32 ID:4WGAo47f(7/7) AAS
>>78
イテレータが返すのはデータ値自体とは限らず参照も返す
特に今回の質問者が返したい可変参照は明確に!Cloneが定義されていてもちろん!Copyでもある
それでも可変参照をイテレータが返すことができてVecへ収容することも可能なのはCloneもコピーも行われないためだ
さらにそれらと全く独立した話としてイテレータ自体への参照/可変参照を返す場合はstd::iter::Iteratorで扱えないためLendingIteratorを使うという話が本題
83
(1): 2024/12/07(土)18:53 ID:MlZHBv1+(4/5) AAS
そんなに移動がしたいならこれでいい

first = into_next(iter); // iterはもう値を所有しない
second = into_next(first) // firstはもう値を所有しない
84: 2024/12/07(土)19:21 ID:8M4lSePd(1) AAS
>>83
それによって新たにできるようになることや新たに生じるメリットは何?
85: 2024/12/07(土)21:52 ID:MlZHBv1+(5/5) AAS
C++でもRustでも変わらないメリットはcloneとdropをしなくてすむことだが

そういえば、Rust固有のメリットは'aが出てこないことと
'staticも出てこないことだな
86: 2024/12/08(日)15:04 ID:vgRddWB1(1) AAS
全然話変わるんだけどPinky Crush新曲のlowercase lifetimeってRust関係あるのかな
87: 2024/12/08(日)22:46 ID:y6R7+MXT(1) AAS
>>61
mutでないiterも出来なくて困ってるとのことなので
スライスのiter()と同じものがLendingIteratorを使わずに書けるよ

struct MyIter<'a, T>(&'a [T]);

fn my_iter<'a, T>(slice: &'a [T]) -> MyIter<'a, T> {
MyIter(slice)
}

impl<'a, T> std::iter::Iterator for MyIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
省15
1-
あと 319 レスあります
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ AAサムネイル

ぬこの手 ぬこTOP 0.008s