1 名前:デフォルトの名無しさん mailto:sage [2022/05/12(木) 18:28:20.99 ID:cuIcFT6k.net] 公式 https://www.rust-lang.org/ https://blog.rust-lang.org/ https://github.com/rust-lang/rust Web上の実行環境 https://play.rust-lang.org 日本語の情報 https://rust-jp.rs/ ※Rustを学びたい人はまず最初に公式のThe Bookを読むこと https://doc.rust-lang.org/book/ ※Rustを学ぶ際に犯しがちな12の過ち https://dystroy.org/blog/how-not-to-learn-rust ※Rustのasyncについて知りたければ「async-book」は必読 https://rust-lang.github.io/async-book/ ※C++との比較は専用スレへ C++ vs Rust https://mevius.5ch.net/test/read.cgi/tech/1619219089/ ※次スレは原則>>980 が立てること 前スレ Rust part14 https://mevius.5ch.net/test/read.cgi/tech/1644596656/
560 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 12:37:42.94 ID:C5b6ywPX.net] >>548 そのベンチが>>539 のつもりなんだけど、これにどういう問題があって具体的には何をしろと? from_fn使ってる分(5)のほうが近いから比較対象を(1)から(5)に変えろってこと? というかそれが分かっているなら他人にやらせるんでなく自分で検証すればいいのでは?
561 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 14:46:42.18 ID:JNpA1ROM.net] >>551 結局、何が原因なん? ジェネリック?それともchecked_add?あるいは変数Some?まさかのswap? Rustスレとしてはコードよりも原因を知りたい
562 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 15:00:02.66 ID:0R8j40RZ.net] >>502 「1.5倍も差があるのは妙だな Rustでは最適化されるのでジェネリックで書こうがそんな差は出ないはず」 これがそもそもおかしい、最適化されようが何だろうが生成されるコードは違うのでMIRなりdisamなりでインストラクション単位で目視すれば一発だろ。ベンチを取る以前の思い込み低レベルな話 そしてほぼ最適化された無駄のないコードだったとしても >>523 ここ5年程度のCPUでは64バイトのDSB境界を持つ小さなループ呼び出しなどが単一のμopsキャッシュに収まる場合があるがコードの配置によって異なり1.5倍程度の差が出ても不思議じゃない。 言ってるのに全く聞かない
563 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 15:48:23.76 ID:kiLfNcoT.net] >>553 その件は1.5倍差あった>>481 がイテレータと関数を比較するという大チョンボをしていたことが原因と判明済 そしてジェネリックか否か自体では速度に差が出ないことを>>502 のベンチが証明済
564 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 17:10:39.22 ID:C5b6ywPX.net] >>554 よく見ろ、それは>>475 の話だ >>481 は両方とも(usize) -> BigUintな関数
565 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 17:16:08.77 ID:LlAtoLIj.net] これだけ時間をか
566 名前:けても原因すら分からずノンジェネリックとの速度差を埋められない状況をコストとして認識できてないのが恐ろしい [] [ここ壊れてます]
567 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 17:31:51.50 ID:H0oyRmek.net] 一般的に、数列を順に求めるイテレータと、 そのうちの特定の数だけを求める関数とでは、 オーダー問題もアルゴリズムも変わってくるため、 >>481 はまた別の問題となっている。 イテレータ同士の比較で1.5倍となっていないことからも、 異なる問題であると理解できるはず。 >>556 ジェネリックとノンジェネリックに速度差が無いことは、 >>502 で既に示されたのだから、 ジェネリックかどうかは一切関係ないと思う。 ジェネリックとは別の問題。
568 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 18:18:03.20 ID:cKPONsWM.net] >>557 >>502 はジェネリックでも実現できるコードをノンジェネリックにしただけ ノンジェネリックならadd_assign, mem::swap, cloneで>>502 のいずれよりも速いコードが書けるが ジェネリックだとchecked_addを使わざるを得ず同じことが実現できない
569 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 18:32:47.55 ID:y1p7Fxu2.net] >>537 では「ジェネリックよりも速いコードがあるならきちんと示そうぜ」と言っていて >>540 の言う違いを理解している感じだったのに いざ本当にコードが出てくるとジェネリクス自体のオーバーヘッドの話に限定して、差は無いと連呼 わざとやってんの?
570 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 19:11:11 ID:sj9oTS9C.net] >>558 > ジェネリックだとchecked_addを使わざるを得ず同じことが実現できない それは違うのではないか? ジェネリックでも自由にCheckedAddAssign等を定義して実現することが可能という話が既に出ている >>492 >>543 一方でノンジェネリックで書いてもオーバフロー対策としてchecked_addは使わざるを得ない つまりどちらが有利とか優れているとかいう問題ではない
571 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 19:45:52.60 ID:btlg3B6B.net] >>560 他人の意見を鵜呑みにしてないでやってみれば? 俺はちょっと試してみたけど結局無理だと確信したよ
572 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 19:54:30.37 ID:hF0KVPZD.net] CheckedAddAssignの定義難しいよね cloneを減らせるうまい定義見せて欲しい
573 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 19:58:01.42 ID:hF0KVPZD.net] >>560 > 一方でノンジェネリックで書いてもオーバフロー対策としてchecked_addは使わざるを得ない つまりどちらが有利とか優れているとかいう問題ではない BigUintの場合はオーバーフローを想定しなくて良いからただのAddAssignで良いよね ジェネリックな実装の場合は考慮すべき事項が増えるというハンデを抱えている
574 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 20:09:35.76 ID:Pauu0yN9.net] 基地同士の喧嘩おもすれー
575 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 21:16:33.76 ID:zfNTYu3X.net] ジェネリックでなくても各i8版~u128版でchecked_add要るんじゃね?
576 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 21:31:30.99 ID:uKz/tAPi.net] >>560 CheckedAddAssignはAddAssignと同じようには実現できないよ 速度差は他の方法で工夫すれば埋めることは不可能ではない
577 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 22:52:52.99 ID:C5b6ywPX.net] このままでは誰も気付かなさそうなのでここでネタばらし >>539 のcriterion版ですがこちらで動かすとこうなりました fibonacci_iter_1 time: [7.3605 ms 7.3655 ms 7.3711 ms] Found 9 outliers among 100 measurements (9.00%) 1 (1.00%) high mild 8 (8.00%) high severe fibonacci_biguint_iter time: [7.5944 ms 7.5967 ms 7.5992 ms] Found 2 outliers among 100 measurements (2.00%) 1 (1.00%) high mild 1 (1.00%) high severe 同程度に遅くなってしまいました 理由は>>548 の通り、せっかく減らしたcloneをイテレータ化するために戻さざるを得なかったからです 一見非ジェネリックのほうが速い結果が出たのは、criterion版がN=50000としていたのに対して、 test crate版は最初に貼られたN=10000から変えずにやっていたためでした criterion版をN=10000で、test crate版をN=50000で計測してみると大体同じような結果になりました N<2^15あたりまでは非ジェネリックのほうがちょっとだけ速いみたいですが、まあ誤差の範疇かと思います そういうわけで>>539 で非ジェネリックのほうが速いと主張したのは嘘です 本気で信じちゃった人はごめんね 最初はcriterionとtest crateの差だと早とちりしたため、ベンチマーク不適切説とか勿体ぶった書き方をしてました >>502 で根拠も無く疑いをかけたのに対するカウンターのつもりで黙ってたんですが、不発になっちゃいました まあでもtest crateってwarm upもしないしサンプル数固定だし、その結果ひどい場合だと>>511 なんか相対誤差10%超えてるし criterion使ったほうがいいよってのは大筋では間違ってないよね 最後に+=でイテレートするこれだけ貼っとくから 某おじはこれに相当する性能のジェネリックなイテレータが書けるまでそういったクソどうでもいい執着に人を付き合わせるんじゃないぞ https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=76cd0aad53f19888900a4b450fd078c5
578 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 23:10:54.19 ID:Pauu0yN9.net] Rust使うやつは全員クズ
579 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 23:14:19.56 ID:xZpQpCco.net] ゴミみてぇに使いにくい
580 名前:デフォルトの名無しさん mailto:sage [2022/06/08(水) 23:33:46.23 ID:1Qgkgfnu.net] >>567 ジェネリックは遅くて使い物にならずRustはクソ言語のいい流れが出来ていたのに邪魔すんなボケ
581 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 00:05:50.09 ID:8AO4ag5u.net] >>567 それが本当にベンチマークしたかった内容なのかな? Nの変化による性能差の変化が重要 Rcでイテレータ返すやつと合わせて確認すればN=50000だと差がなくなる理由も分かる
582 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 01:08:31 ID:b8HehfnZ.net] >>567 裏切り者め 隠し通せよ
583 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 09:43:05.84 ID:m8hzuB37.net] >>567 結局ジェネリックに書いても非ジェネリックでも速さはほぼ同じなのかよ どんな方法で書いても結果を返すためにclone相当が最低1回は必要で >>502 のジェネリック版はclone相当がchecked_addでの1回のみだからこれ以上は速くできないってことか
584 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 11:12:09.28 ID:5tn+SNbG.net] 複オジ必死やなw
585 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 11:39:59.58 ID:gQa8Lild.net] iterなんだけど let v = vec![1, 2, 3, 4]; v.iter().filter(|&x| x % 2 == 0).cloned().collect(); v.iter().map(|&x| x * 2).collect(); filter()はcloned()が必要でなぜmap()は必要ないのか
586 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 11:41:07.83 ID:gQa8Lild.net] まちがえたこうだ let v = vec![1, 2, 3, 4]; let result_1 = v.iter().filter(|&x| x % 2 == 0).cloned().collect(); let result_2 = v.iter().map(|&x| x * 2).collect();
587 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 11:52:52.81 ID:WWB1ag70.net] >>573 IteratorのItem生成のためにcloneが必要という話なので 参照返すとかRc<RefCell>にするとかすればまだ改善する余地はありそうではある
588 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 14:32:02.03 ID:BXa7hn4f.net] 「Atom」の開発者が究極のコードエディターを目指す ~「Zed」の開発が始動 「Electron」を捨て、Rust言語を採用。GPUI、tree-sitterなどで武装し、超高速なコードエディターに https://forest.watch.impress.co.jp/docs/serial/yajiuma/1374986.html
589 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 14:58:44.89 ID:G7q6UoxI.net] 「重要」でスレ内検索かけると……
590 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 16:58:07.35 ID:/uOnDbzK.net] >>575 Vec<i32>のiter()は&i32のイテレータ filterした結果も&i32なのでVec<i32>でcollectしたければcopiedやclonedが必要 Vec<&i32>のままcollectするならclonedは不要 mapの例はx * 2でi32が新たに生成され map以降は&i32ではなくi32のイテレータになるので cloned無しでVec<i32>にcollectできる
591 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 17:07:43.03 ID:3qzGL8h6.net] >>577 Rc版はmake_mutにすれば呼び出し側が参照をつかんでる時だけcloneにフォールバックしてくれる つかんでなければcloneしないので高速 全ての値をつかむようならRcを使わないやり方より少し遅くなる
592 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 20:30:30.68 ID:sXhLSFat.net] >>355 はRustだと末尾呼び出しの最適化が効くの? 末尾呼び出し最適化必須のschemeですら自動的には最適化されず、人間が意味を解析して、アキュムレーター使って末尾再帰になるようにしましょうって練習問題になるくらいなのに。 Rust凄い!!
593 名前:デフォルトの名無しさん mailto:sage [2022/06/09(木) 21:24:26.48 ID:xbJg8ij+.net] >>581 簡易的なstreaming iteratorにする方法もあるよ
594 名前:はちみつ餃子 mailto:sage [2022/06/09(木) 22:43:27.67 ID:k8dtcEck.net] >>582 どういう理解をしてるのかようわからんが、 >>355 はいわゆる末尾呼出しではないよ。
595 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 00:02:10.12 ID:/2sYVq21.net] https://twitter.com/Ray__March/status/1523717266730151936 Crab Rave (deleted an unsolicited ad)
596 名前:582 mailto:sage [2022/06/10(金) 12:26:19.22 ID:xMTaqdcz.net] >>584 340くらいから末尾呼び出し最適化の話題があって、355の2で「リリースモードだとスタックが溢れない」と書いてあったので、末尾呼び出し最適化が効いたのかと思いました。 十分なスタック容量があっただけ? 1+count(n-1) を count(n-1, acc+1) に書き換えてくれる最適化があるのかな、と思いまして
597 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 12:39:41.49 ID:awrGQFqA.net] >>586 生成されたバイナリを見た方が良いよ https://godbolt.org/z/Kcd6zf68e 定数たたみ込みでnopになってるっぽい
598 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 12:44:00.71 ID:NmVzwec3.net] >>583 ストリーミングイテレータを試してみたけどRc使ったほうが少し速かった ただ呼び出し側が参照をつかんだままにするとコンパイルエラーにしてくれるのでRcより望ましいケースが多々ありそう
599 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 13:14:03.27 ID:/2sYVq21.net] streaming iterator! そういうのもあるのか 自分への参照を返せるんだね 使うかどうかは分からんけど覚えておこう
600 名前:582 mailto:sage [2022/06/10(金) 17:55:03 ID:k70t2J8V.net] >>587 すまん
601 名前:はちみつ餃子 mailto:sage [2022/06/10(金) 20:18:18.95 ID:din4Kjb/.net] >>586 すでに >>587 が指摘しているが、定数畳み込みが起こっている。 入力が定数で、かつそれに対する演算が副作用のない基本的なものであった場合に定数畳み込みがされやすい。 定数ではない場合でもこの関数 count は mov rax, rdi ret になってて、入力をそのまま返す形にまで最適化されるので末尾呼出しがどうこうというレベルのものではなくなっている。 最適化というのは、レジスタ割り当てなどは理論的な背景がはっきりしているが、多くの細々としたものは「大量の置き換えパターンを辞書のように持っている」という物量で押し切る泥臭いものだったりするので (それをやりやすいようなデータ構造とかに工夫はあると思うが) 結局のところは投入されたリソースが多いやつが強い。 ちなみに Scheme の末尾呼出し最適化は言語仕様で要求する最低限度がそれだけ (しかし常にやらなければならない) という意味であって、それ以上の最適化をやっちゃ駄目という意味ではないよ。 最適化をどのレベルまでやるかは処理系次第。
602 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 20:27:25.22 ID:VliTcE7P.net] こいつが出てくると結論が1つも分からなくなる
603 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 21:05:43.32 ID:uz7MKgqc.net] 複オジと同じ臭い
604 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 21:45:41.77 ID:iyAWtrh4.net] 汚文章は汚コードの兄弟 同じ親から生まれてくるもの
605 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 22:32:01.13 ID:r0Sf5PMX.net] 最適化の話はかなりコンパイラーに詳しくないとなぜそうなるかって分からないだろうからな コンパイラーの最適化について話せる奴はプログラミング中級者以上だろ。 (本職プログラマなら話せないと知識なさすぎと言われるだろうが) 趣味でプの俺は永遠に初心者レベルでそんな知識ないから、こいつ何を言っているんだ?だが
606 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 22:32:11.19 ID:+N1EN6wu.net] まぁ要するに ×××という最適化処理が処理系の規格として定められているのなら処理系の開発者(=コンパイラとか作る人)はその最適化を実現しないといけないしそれを利用するプログラマは処理系が”上手いことやってくれる”と期待していい、しかしそれが言語規格上は必須とされてない処理については処理系が“うまいことやつてくれる”と基本は期待してはいけない けど、規格で求められてないような高度な最適化処理を“してはいけない”わけではない、最新の理論で見つかった最適化処理など取り入れる分には好きにして構わない という意味でしょ Haskellのメモ化処理とかでもよく出てくるよ GHCって言うすごい処理系があってHaskellの標準規格では全然定められてないような最適化処理をバンバンやってくれるから“なんでこんなにはやいの?とりま作っただけなのに”と思うこと時々あるからな
607 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 22:36:04.99 ID:3HE2W+m8.net] 最適化と言えば&mutがnoaliasになって高速化したコード出会ったことある人居る?
608 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 22:56:48.93 ID:/Qg1cUoJ.net] >>596 要するに~ 元の説明より長なっとるやないかーいww 脳みそ整理整頓してこんかーいww
609 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 23:03:01.48 ID:EifRM46R.net] >>595 初心者自演乙オジ
610 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 23:39:18 ID:QxuEFd4p.net] またいつもと同じパターン 善人 = 情報や説明やコード等を書いてくれる人 悪人 = 文句や批判だけの人 >>597 Rustでは基本的に二つの & mut がaliasになることはないからnoaliasでいいけど LLVMのバグが見つかったりやRustコンパイラの改修などで変遷を経てきてるみたいね > Rust 1.0 ~ 1.7 noalias enabled > Rust 1.8 ~ 1.27 noalias disabled > Rust 1.28 ~ 1.29 noalias enabled > Rust 1.30 ~ 1.54 noalias disabled > Rust 1.54 ~ noalias enabled
611 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 23:52:37.74 ID:q3uEdydr.net] 仕様ころころゴミ言語
612 名前:デフォルトの名無しさん mailto:sage [2022/06/10(金) 23:57:33.08 ID:Vy8jfUtT.net] ソースこれですか https://stackoverflow.com/a/57259339
613 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 00:21:37.71 ID:nVHax23k.net] >>602 「rust add assign optimize site:stackoverflow.com」でトップヒットだったわw どおりでね
614 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 00:47:00.69 ID:41aFXNPT.net] >>601 Rustの仕様は変わっていない LLVMへの最適化指示のうちの一つをLLVMのバグ発見のため一時的にオフとしていただけ
615 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 00:53:30.81 ID:6T6IERuk.net] そんなつまんねーのに反応すんなよ……
616 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 01:51:51.23 ID:coFBEVyx.net] マッチポンピング好きだねぇ
617 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 11:14:20.05 ID:FpznSlgy.net] そろそろRust製の有名なソフトウェア作ってからビックマウスしてくださいね、Firefox以外で
618 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 11:39:14.69 ID:fd4RDbWP.net] >>606 マッチポンプも過疎スレのにぎわい
619 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 11:54:00.75 ID:sRR0HfwK.net] TechEmpower Round 18で1.5倍の差を付けて堂々の1位をかっさらったactixは有名ソフトウェアではない了解
620 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 15:51:26.10 ID:Lxou0O6d.net] DiscordとかDropboxとか
621 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 16:19:59.18 ID:C3/u0lQ5.net] WinとかLinuxの中身ですでに使われてなかった?
622 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 18:52:01.33 ID:BGPUwt90.net] >>593 同じ臭いも何も同一人物だろ
623 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 19:26:39.50 ID:WsHL0uxM.net] >>611 Linuxはまだ winは確実なソースあったっけ? OS系だとAndroidでは使われてる(まだデフォルトで有効ではないけど)
624 名前:デフォルトの名無しさん mailto:sage [2022/06/11(土) 23:25:25.63 ID:HlAQKNMT.net] なんでRound18なんて大昔の過去を?
625 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 06:12:09.52 ID:6S+GFICB.net] >>612 どうでもいい >>613 同じくどうでもいい
626 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 17:11:51.09 ID:tUHADwRi.net] Rustはver2.0にはなりませんって言ってるけど実質はとっくの昔にver2.0になってる
627 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 19:14:45.66 ID:geXDvND7.net] >>616 どういうこと?
628 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 20:36:02.36 ID:nrxswUhC.net] >>562 >>566 CheckedAddAssignにこだわる必要はないため、発想を転換して、 checked_add()の原関数であるoverflowing_add()を用いることで、 overflowing_add_assign()を用意して同じようにbool値を返せば解決する 具体的には以下のように引数はadd_assign()と同じでbool値を返せばよい trait OverflowingAddAssign { fn overflowing_add_assign(&mut self, rhs: &Self) -> bool; } オーバーフローするi8型〜u128型にはoverflowing_add()があるため実装はこうなる let is_overflow; (*self, is_overflow) = self.overflowing_add(*rhs); is_overflow この3行のコードでちゃんと最適化されるかどうかを確認するため、 単純にadd_assignを用いた場合、すなわち「*self += rhs」と比較すると https://godbolt.org/z/WP3En8xM8 のアセンブリ出力となり、オーバーフローを返す以外は同一に最適化されることが確認できる 一方でオーバーフローしないBigUintなどの型への実装はこうなる *self += rhs; false つまりオーバーフローの結果として常にfalseを返すので、 こちらは使う側でオーバーフローの扱いが消えてadd_assign部分のみに最適化される したがってこのOverflowingAddAssignを用いてジェネリックに書けば、 どちらの型の場合であっても、非ジェネリックに書いた時と同一コードとなる
629 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 20:47:24.48 ID:nrxswUhC.net] >>577 一般的に参照返すイテレータ類を実装する場合の注意点として、 1. let x0 = x_iter.next(); 2. let x1 = x_iter.next(); 3. ここで x0 の指す値を使う 順にこのような使い方をした時の挙動として、以下4パターンが考えられる A. ✕ 実行時エラーとなる B. ✕ x0の指す値が変化してしまう (次のx1の指す値と同一になってしまう) C. ○ x0もx1もそれぞれ正しい値を指す D. ○ コンパイル時エラーとなる Rcとget_mut()を使った>>511 のコードがNGのパターンA.で、これを避けるために、 Rc<RefCell>を使う提案のようだが、それもNGのパターンB.となってしまう Rcとmake_mut()を使えばパターンC.となり、これがRc利用の場合の解となる しかし参照を返すイテレータ自身がmake_mut()でclone()するのは役割として過剰である 切り分けとしてはイテレータを使う側が必要に応じてclone()するのが望ましい そういうコードへ適切に誘導できる道が、コンパイル時エラーで示すパターンD. 具体的には、似非IteratorであるStreamingIteratorを用いるか、 Rust本命のGATsを用いたLendingIterator (=GATs適用後のIterator) を用いると、 clone()が必要な場面ではコンパイル時エラーにより知らせてくれる もちろん普通にnext()ループ内の利用ならばclone()の必要なくコンパイルが通る
630 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 20:59:35.22 ID:nrxswUhC.net] 実際に >>618 のOverflowingAddAssignを用いてLendingIteratorで実装すると 以下のようになり、GATsを用いている以外は現状のIteratorともちろん同じ形 自己参照を返せるようになった点のみ異なる impl<T: OverflowingAddAssign> LendingIterator for Fibonacci<T> { type Item<'a> = &'a T where Self: 'a; fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> { if self.is_overflow { return None; } if self.is_first { self.is_first = false; } else { self.is_overflow = self.p.overflowing_add_assign(&self.q); std::mem::swap(&mut self.p, &mut self.q); } Some(&self.p) } } is_first処理は >>511 のコードでの「iter::once(p.clone()).chain(...」部分であり必須 また、前述のようにBigUintで用いれば is_overflow が常にfalseのため最適化で消えて、 値の更新部分は「self.p += &self.q」のみが残り非ジェネリックと同一コードとなる したがって、上述のコードがどの型でも最善に動作するコードとなるだろう
631 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 21:33:27.12 ID:HOCAPH7I.net] NAVERまとめを彷彿とさせるレス乙 3~4日もかけて頑張って調べたのは讃えるが 特質の異なるものを必要もなくジェネリック化することがアンチパターンだということに早く気づいてね
632 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 21:51:32.06 ID:rC/Ton17.net] これは同じものだからジェネリックでいいんじゃね
633 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 22:02:56.78 ID:geXDvND7.net] >>620 構造体メンバーであるis_overflowが常にfalseであることが分かるほどコンパイラ賢いんだっけ? 実際に生成されるコード確認した?
634 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 22:16:28.43 ID:McWr7xMA.net] add系は#[inline]だから大丈夫
635 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 22:22:02.34 ID:geXDvND7.net] >>624 構造体メンバの値はグローバル変数なんかと同じで関数外で値が変更される可能性があるので メンバが特定の値しか取らないことを暫定として最適化するためには、 crateの範囲を超えてプログラム全体で値が設定されうる箇所が他にないことを確認するか メンバが可視な範囲で確認する必要があると思うけど、 前者をやるためにはリンク時最適化が必要だし 後者ならメンバの可視性をLLVMに渡さないといけないと思う rustcとLLVMはそこまでやってるの?
636 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 22:54:00.11 ID:E86JsxIR.net] rust結構面白いからマイクロソフトがVisualStudioでRustでWindowsFormを作れるようにしてくれればなあ
637 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 22:59:17.60 ID:MphJhZqp.net] >>618 それが>>566 の2行目で書いてる工夫のことだよ boolではなくchecked_add使ってOption<()>返すメソッドにしておけば?演算子でシンプルに書ける
638 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 23:07:42.57 ID:McWr7xMA.net] >>627 assignでない演算は生成のため内部でcloneが発生して無駄と既に結論が出ている
639 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 23:11:14.31 ID:0LaPlWrL.net] GATがstableになるの意外と近い予定なんだな 年単位で先のことかと思ってた
640 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 23:18:22.58 ID:H16c0lbs.net] >>625 Rustでそれは起きない 書き換えるには所有権か&mutが必要でコンパイラは全て把握している 更に構造体のメンバーはpub指定がない限り他者はアクセス不能 つまり今回ならばnext()しかメンバー書き換えしないとコンパイラは確定できる
641 名前:デフォルトの名無しさん mailto:sage [2022/06/12(日) 23:25:01.40 ID:geXDvND7.net] >>630 その最適化するのはLLVMだけどLLVMが最適化できるだけの情報を渡してるの?というのが聞きたいこと
642 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 00:14:58.10 ID:RutuvYDu.net] >>623 その通りRustコンパイラが賢いことを確認したよ is_overflowが常にfalseとなることを察知してNoneを返すことが無くなったみたい Noneが来ない利用側のwhile let Some(n) = iter.next()は無限ループのコードとなっちゃった さらにwhile loopより後ろのコードは永遠未達と判断されて完全に消えた
643 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 00:32:02.84 ID:XmIGhHAx.net] >>628 checked_add使うのはプリミティブだけだよ BigUintはadd_assignで常にSome(())
644 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 00:46:44.89 ID:BEV+i+nu.net] >>620 GATってIteratorとか既存TraitのAssosiate Typeに直接ライフタイム書けない仕様になったの? LendingIteratorみたいに別のTraitを使わないといけないようならイテレータ関連の仕組みが2重なって使い勝手が悪い
645 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 00:50:16.18 ID:WmCB7dh7.net] >>633 意味不明 Some(())/Noneにするならば>>618 のbool値のコードで十分
646 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 00:56:09.87 ID:WmCB7dh7.net] >>634 もちろん出来るようになる 今は無理だからRust公式ブログで解説された例に倣って仮にLendingIteratorとの名で定義して使うなどする
647 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 12:04:19.24 ID:GDAgVCx4.net] >>632 おー、そんな賢いんだ。すごい ちなみにfn mainとイテレータの定義は同じcrateに含まれている? lib crateでイテレータを定義してbin crateから使った場合にどうなるかも気になる
648 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 14:28:57.42 ID:HonuYlRO.net] >>626 こういうMicrosoftからのサポートは俺も期待してる VC++よりもRust書きたい
649 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 17:16:12.55 ID:GB/2aB1F.net] やめてくれ 汚コードまみれになる
650 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 19:44:34.63 ID:oVc0GyRX.net] 乱数系のモジュールの仕様変更がかなりガッツリあったみたいなんだけど Rustってこういうことよく起るの? なんかWeb系みたいなノリを感じたんだが合ってる?
651 名前:デフォルトの名無しさん [2022/06/13(月) 19:57:14.15 ID:86dwWfAN.net] なんのはなしだ
652 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 19:58:13.01 ID:8KDu5nut.net] >>640 人に読んでもらう文章は重要なところ省いたら読んでもらえないよ
653 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 19:59:25.24 ID:GDAgVCx4.net] >>640 標準ライブラリで破壊的変更はほとんどない 外部crateなら概ねsemverに従ってるし lockfile の仕組みもあるから、 以前ビルドできていたものがビルドできなくなることもほとんどない
654 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 20:37:45.98 ID:XXqnAuVB.net] >>638 サポートってどの程度のサポートを期待しているんだ? MSがRustコンパイラー出せばWindowsのRust用フレームワーク出すんだろうがな 出さないなら、C/C++/C#のAPI/フレームワークをRustからとりあえず使えるようにしました 程度のサポートになるだろう。 期待しているのはRust用フレームワークであってRustからとりあえず使えるよじゃないだろ? [] [ここ壊れてます]
656 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 20:37:53.20 ID:oVc0GyRX.net] >>643 あれ外部ライブラリか しかし乱数系の標準ライブラリってまだRustにないのか やぱ若い言語だなRust
657 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 20:43:42.90 ID:cs6TlBtz.net] >>645 若いというか意図的に標準ライブラリから外してあるよ 理由は標準入りしてしまうと破壊的変更ができなくなって腐るから だから将来的にも標準に入る予定はないと思う
658 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 20:52:20.46 ID:oVc0GyRX.net] >>646 意図的に外してるの? ふーん、それはそれで面白い
659 名前:デフォルトの名無しさん mailto:sage [2022/06/13(月) 23:01:34.06 ID:JmWkv6oB.net] >理由は標準入りしてしまうと破壊的変更ができなくなって腐るから なんという本末転倒感
660 名前:デフォルトの名無しさん mailto:sage [2022/06/14(火) 00:25:58.88 ID:DOq4xEj+.net] 基本的にRustはシンプルに最小限の言語構成部分しか標準ライブラリに持たない方針 つまり各プログラミング言語毎に標準ライブラリの意味合いや範囲が異なるのと同じ だから乱数でも正規表現でも何でもRustでは外部クレートに存在する 非同期だって基本構成部分のasync/await/Futureは言語として持つけど 非同期ランタイムや非同期ライブラリは外部クレート