Rust part14

■ このスレッドは過去ログ倉庫に格納されています
2022/02/12(土) 01:24:16.59ID:XYE+Rws6
公式
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 part13
https://mevius.5ch.net/test/read.cgi/tech/1636247099/
2022/04/04(月) 16:48:14.52ID:y2zkcNcq
>>568>>567 宛て
2022/04/04(月) 16:57:22.99ID:k6lsU7ys
>>568
ありがとう。
2022/04/04(月) 23:27:32.81ID:tN0jAerG
let mut foo: Box<dyn Fn() -> usize> = Box::new(|| 1);
foo = Box::new(|| 2);
// ↓ このケースならばFn()使わずともfn()で行ける
let mut foo: Box<fn() -> usize> = Box::new(|| 1);
foo = Box::new(|| 2);
// ↓ さらにBoxも不要となる
let mut foo: fn() -> usize = || 1;
foo = || 2;
2022/04/04(月) 23:30:29.31ID:Uk+ayJmh
unwrapじゃなく;がunwrapの代わりになったらよかったのに、構文解析に;なんてもう使ってないでしょうに
2022/04/04(月) 23:41:54.63ID:3iHsJPtq
>>572
なぜ?
>>552にもあるけどunwrapなんて非常に特殊な時のみ使うもの
論理的にNoneやErrではないと保証できる場合は使うべきだが頻度も限られる
残りはNoneやErrの時にpanic終了という簡易エラー処理の場合でしかunwrapは使われない
その簡易エラー処理をしたい場合でも?オペレータでエラーを最上位に集めて1カ所だけエラー表示を設けるとpanic unwrapを無くせる
2022/04/05(火) 04:14:10.02ID:opdT/MNM
>>572
文は式と区別するため必ず「;」を伴う
例えば関数やブロックの最後(=「}」の直前)に
「;」があると文となり返り値が()となる
「;」がないとその式の値が返り値となる
そしてブロックやif-elseやloopはその値の式なので文を形成する最後に登場する時は「}」の直後に「;」が来る
このように他のプログラミング言語とは異なりRustでは「;」の存在は重要である
2022/04/05(火) 07:02:36.93ID:l+kYPJyP
ブロックの最後の式がブロックの評価値になるのはRubyもそうだよ
だからと言って;にunwrap割り当てろとは思わないけど
2022/04/05(火) 11:45:54.41ID:AUzgrMft
unwrap はそれなりに目立つべきだろう。
一文字でどうにかするのはよろしくない。
2022/04/05(火) 15:21:06.80ID:owP7OoVB
unwrap連打することもあるんだからないな
他の言語みたいにunwrapを!で書けるようにするほうがマシ
2022/04/05(火) 16:32:58.11ID:bH2gxj8m
むしろunwrap_or_dieとかにして欲しいくらいだな
2022/04/05(火) 17:27:14.20ID:jhOIIm2D
使いにくく書きにくくさせることで
馬鹿に知らず識らずマナーを強いてるんだよ

だからJavaでアクセッサ書くのダルいと怒ってるのと
rustでmutってタイプするのダルいと怒ってるのと
unwrapってタイプするのダルいと怒ってるのと

言ってる人はみなおなじバカ
ちなみに馬鹿に迎合してプロパティを準備してみせたウルトラバカ言語がC#
2022/04/05(火) 17:46:43.00ID:QA37bGpe
>>578
これすき
2022/04/05(火) 18:59:43.74ID:ZwTPjiXX
だったらfnなんて短さ、どうなん?とは思うけどな。
2022/04/05(火) 19:10:52.07ID:5iTMb1Xf
予約語と比較してどうする
2022/04/05(火) 19:39:53.86ID:RVaVR3wo
unwrap()は論理的に安全に剥がせると明確になる特殊な場合のみ使うべきもの
見てすぐ明確でない時はコメントを付けること推奨
2022/04/05(火) 20:30:38.50ID:AUzgrMft
エラーメッセージ中で便宜上のライフタイム (?) として '1 というのが出てくることがあるけど、
これは一個目の引数のライフタイムという解釈でいいのかな?
2022/04/05(火) 20:31:56.58ID:iTms6SBF
unwrap()はリリースビルドでコンパイルエラーにして欲しい
Elmみたいにデバッグビルドでのみ使えるって感じで
2022/04/05(火) 20:33:43.79ID:mQ5E2nDT
unwrapでpanic起こしたら死刑
2022/04/05(火) 20:45:42.53ID:RriiMuS9
>>585
論理的に剥がして安全なことをコンパイラが追いかけてくれるならそれもありだけど
現状で全面unwrap禁止は無理
2022/04/05(火) 20:52:13.73ID:VJaRyQKx
書き捨てのコードでいちいち例外処理書かされるの面倒だからunwrapは必要
2022/04/05(火) 20:54:37.54ID:AUzgrMft
unwrap を排除したらそれぞれで unwrap みたいなものを定義して使うようになっちゃうのがオチだよ。
2022/04/05(火) 20:56:22.37ID:m6fZyHop
>>583
コメントつけるならexpectでpanic時メッセージ出した方が良いのでは
2022/04/05(火) 21:09:00.11ID:ks20fz6N
>>590
論理的に起きない場合にexpectは単なるコードの無駄
エラー発生時にパニック終了していいプログラムで補完エラーメッセージとしてexpectを使う
2022/04/05(火) 21:21:53.89ID:m6fZyHop
>>591
趣味の問題な気がするけどその理屈だと論理的に起きない場合はコメントの無駄とならない?
それともコミュニティーで広く普及してる慣例があるのかしら
2022/04/05(火) 21:39:41.29ID:u7gEIfJv
一般的に、論理的に正しいがコードを見てすぐに把握できない可能性がある場合は、コメントを付ける慣例
2022/04/05(火) 21:55:10.17ID:l+kYPJyP
>>591
コードの無駄というのは正確には何が無駄なのだろう
文字列分の領域?
2022/04/06(水) 00:04:36.01ID:L0tmrFUv
>>578
Javaっぽいですね
2022/04/06(水) 00:19:00.36ID:QeRv7PuV
>>575
Null条件演算子とか他言語には一般的になって来てるけど、ライブラリでしかないはずのOption,Resultが言語の中核みたいになってるRustが
採用するとは思えない。Option条件演算子?
2022/04/06(水) 00:29:51.46ID:NjGChFO7
他でのNull合体演算子つまりNull時にデフォルト値とする演算はRustではunwrap_or
もちろんそれら他の言語ではT型そのものにNullがありミスを防げないが
RustではT型とOption<T>型に分かれているためミスが起きない
2022/04/06(水) 03:59:22.01ID:pOKs9eQ1
いや言語的な特性のこと言ってるわけじゃねーからwいちいち知識疲労で解説しなくていいからw
2022/04/06(水) 08:23:07.29ID:V4186sOU
ルビー君と同じ病気だよね
しかも間違ってるし
2022/04/06(水) 09:21:37.82ID:X0SajXCN
>>596
rust の場合 try {} 構文が対応するものかな
try { a?.b?.c }
みたいに書ける
2022/04/06(水) 10:07:13.82ID:LgAnKe/v
>>600
try構文使わずとも書けるよね

fn main() {
let a = Some([[1, 11], [2, 22], [3, 33]]);
let x = (|| Some(a?.last()?.first()? * 100))();
assert_eq!(x, Some(300));
}
2022/04/06(水) 10:33:16.53ID:Dw8vI7FQ
>>596が言ってるのはnull条件演算子
>>597が言ってるのはnull合体演算子

そりゃ話が通じるわけない
2022/04/06(水) 11:49:10.11ID:rSNzLcDe
>>597
C#とかSwiftとかKotlinとかNull safetyを備えてる言語も勉強してね
ちょっと恥ずかしいよ
2022/04/06(水) 17:06:15.48ID:SXJV6JXP
>>601
なるほど、クロージャにすれば?使えるって発想なかったわ
2022/04/06(水) 18:11:52.43ID:9SYtmHqH
なるほどじゃねーよwww
2022/04/07(木) 04:17:47.69ID:tEZE72Zs
stableでどうしてもtryっぽく書きたい場合の苦肉の策でしかないな
2022/04/07(木) 07:08:56.80ID:GJZ5/Xn8
クロージャ(ラムダ)の即時実行は他の色々な言語でも行なう頻出パターン
Rustでは他にもforやwhileから値を返したい時などにもクロージャの即時実行で行なう
608デフォルトの名無しさん
垢版 |
2022/04/07(木) 07:19:00.45ID:M1TIObhS
これって、公開するメソッドのの数だけディスパッチャメソッドが増えてく感じなの?
https://tourofrust.com/81_ja.html
結構めんどくさいような気もするんだけど・・・・こういうのってエディタの拡張とかが勝手やってくれたりとか、支援みたいなのあるの???
2022/04/07(木) 07:36:57.92ID:GySucWIC
>>608
プログラマーは全く何もしなくてよい
dyn Traitの場合はメソッド数分の関数ポインタを持つディスパッチ用テーブルが各使用型毎に自動的に生成されて実行時に自動的に適用される
impl Traitの場合は使用メソッドの関数がモノモーフィゼーションすなわち各使用型毎にコンパイル時に展開される
逆にプログラマーが自分で分岐処理する第三の方法としてenumに各使用形を収容してmatchによる分岐処理があってこの方法が有利になるケースもある
2022/04/07(木) 10:32:38.29ID:bzCO3d2+
C++ だと静的な多相はテンプレートで、動的な多相は仮想関数 (抽象クラス) でやってるわけだけど、
Rust だと dyn だけで切り替えられるってわけだな。
2022/04/07(木) 12:45:48.26ID:Qjh8kwCx
>>608
tour of rustでRustに入門するのはやめたほうがいいぞ
中身が更新されてないしGoと違ってtourから始めるのは害にしかならないから
2022/04/07(木) 13:22:38.91ID:bzCO3d2+
わかる。
Rust の型システム・所有権システムは理屈が分かってないと慣れでどうにかなるもんではない。
理解した上でなら手を動かしてみるのは悪くないと思うけど。
613デフォルトの名無しさん
垢版 |
2022/04/07(木) 15:06:14.55ID:pUyNlzjX
>>612
それはどんな言語も多かれ少なかれありそう
Cのポインタもそうだしね
2022/04/07(木) 18:17:40.12ID:6J24GmAj
>>607
クロージャの即時呼び出しは基本的に言語機能が足りない場合のワークアラウンドでしょ
2022/04/07(木) 18:20:36.61ID:6QFUvNfL
クロージャは引数と戻り値を推論してくれるからこそだね
関数でも、なんかの条件付きでもいいから推論してほしいわ
2022/04/07(木) 18:21:01.63ID:6QFUvNfL
推論というか、型推論ね
2022/04/07(木) 18:33:18.44ID:6J24GmAj
関数含むモジュールレベル定義の型推論はやろうと思えばできるけど
コンパイル時間への影響がでかいのと、ドキュメント的な意味で型を書いた方がわかりやすいという理由で
敢えて対応していないとどこかで読んだ気がする

とはいえ戻り値のimpl Traitは制限された形での型推論と言えるんじゃないかな
2022/04/07(木) 18:34:30.25ID:QZwctsvV
>>614
Rustでは型指定しなくて済む利点もあるしクロージャと関数の使い分けの一種じゃないかな
もちろん今回のケースはreturn値を取る別種のブロックがあれば済むけども
それをわざわざ導入しなくてもクロージャ即時呼び出しで十分
2022/04/08(金) 04:35:42.40ID:fis9zD2L
Rustのコンパイルの遅さは型推論とかじゃなく、cargoという非常に悪い仕組みのせい
2022/04/10(日) 02:43:45.04ID:NYexxOz5
そんなことないよ
cargo build --timings いいね
2022/04/10(日) 11:44:22.72ID:UjiUu+PI
Rust 1.60来てたか
2022/04/12(火) 10:03:48.28ID:mYiJhF+M
OnceCell<T> って &'static T が取れるわけじゃないんですのん?
2022/04/12(火) 10:14:36.57ID:mYiJhF+M
まちがえた
× OnceCell<T>
○ const Lazy<T>
2022/04/12(火) 10:20:45.37ID:9tHmQ2kh
getでOption<&T>が取れる
初期化してなければNone
2022/04/12(火) 10:26:05.90ID:9tHmQ2kh
LazyならDerefを適用させて使う
*lazyで&Tや&mut T
2022/04/12(火) 10:46:54.62ID:mYiJhF+M
https://play.rust-lang.org/?version=nightly&;mode=debug&edition=2021&gist=22ed821be70a494615ca8a661e98b78f

ごめんこういうこと
実際使ってるとき&'staticが取れないのが原因だと思ってそう書いちゃったけど違う原因かもしれないです
2022/04/12(火) 11:20:51.11ID:9tHmQ2kh
それはconstではなくstaticで宣言
2022/04/12(火) 11:33:29.72ID:/UwhBms2
プログラム開始時点での有効性を保証できないから何となくだけどコンパイラの事情で無理そう

&'staticって↓みたいな使い方もできるからLazyだとBの参照先が初期化済みか分からない
static A: u32 = 0;
static B: &'static u32 = &A;
2022/04/12(火) 11:37:37.75ID:9tHmQ2kh
nightlyのstd::lazy::Lazyではなく
stableでも使えるonce_cellを使用
そのコードと同じ例がこれで動く

use once_cell::sync::Lazy;

static LAZY: Lazy<i32> = Lazy::new(|| 92);

fn main() {
let a: &'static i32 = sub();
println!("{}", *a);
}

fn sub() -> &'static i32 {
&*LAZY
}
2022/04/12(火) 11:44:54.53ID:mYiJhF+M
あーなるほど
なぜか'staticでmutableなのがstatic、immutableなのがconstと勘違いしてました
constって使用の度に式展開するやつだったんですね
temporary valueなんて無いじゃんとか無限に悩んでた

ありがとうございます
2022/04/12(火) 11:47:13.23ID:9tHmQ2kh
>>630
constはコンパイル時点で定まる定数
2022/04/13(水) 09:59:43.40ID:Ee+AuAP4
こんな事も分からない触ってるだけで偉いと勘違いするゴミ言語
2022/04/15(金) 00:23:00.39ID:jmI/h0lt
>>613
プログラムのポインタ(メモリアドレスを参照するもの)は
ポインタのメタファだから元のポインタを知ってれば理解できるが、
substructural type systemはtype systemの一種でtype systemは
型理論を元にした体系的な理屈だから理屈が理解できなきゃ理解できないから全く別の話。

>>612の言う「慣れでどうにかなるもんではない」っていうのはつまり、
わかった気になってなんとなくで書いてるやつはまだ理解してないって話でしょ。
2022/04/15(金) 00:36:10.15ID:8Ev0Y6We
ソフトウエアを書くにはカテゴリー論から勉強しろということかな?
2022/04/15(金) 00:46:18.85ID:9XxTBRIR
名言もらいました
ポインタはポインタのメタファ
2022/04/15(金) 00:56:52.75ID:w32fyljo
>「慣れでどうにかなるもんではない」っていうのはつまり、
>わかった気になってなんとなくで書いてるやつはまだ理解してないって話でしょ。

全然違う。
型システムより先に文章を理解する訓練をした方がいいぞ。
2022/04/15(金) 01:20:52.56ID:+d47tguH
>>612
他の言語と同様にRustもそんな難しいことしていないから大丈夫
論理とメタ的な考え、例えば高階やジェネリクス等、ができる普通の人ならばRustの理解は容易い
2022/04/15(金) 08:25:31.44ID:xhqbcuaF
>>637
さすがにそれを「普通の人」というのは無謀。
2022/04/15(金) 08:41:02.84ID:WzhbtFPJ
100点オジサンや複製オジサンみたいな自分は理解してるつもりの勘違いさんが一番迷惑
2022/04/15(金) 08:59:01.96ID:uOSWEI+/
>>638
普通のプログラマーなら他の言語でクロージャ(ラムダ等)くらいはさすがに使ったことあるから高階は大丈夫なはず
ジェネリクスもスクリプト言語などの動的型付け言語なら計らずともそのままジェネリックな関数となってる

そこでRustでのみ必要となる概念はそのジェネリックな関数内を安全な操作とするためのトレイト境界の指定
これはコンパイラがエラーとして教えてくれるため指定を忘れることがない
だから普通のプログラマーなら大丈夫じゃないかな
2022/04/15(金) 10:17:08.40ID:xMTiu+TR
相変わらず複製おじさんは不勉強でキツイな
「普通の人」は他の言語でジェネリック使ったことあるからこんな恥ずかしい長文を書かない
2022/04/15(金) 10:53:34.01ID:aXBzZfpz
そうでなくRustではtrait境界が足りなければコンパイルエラーで指摘されるからスクリプト言語から来た人でも困らないって話やろ
2022/04/15(金) 11:18:53.45ID:/A+hDicd
そんなことよりこのエラーの意味を教えてくれ

https://play.rust-lang.org/?version=stable&;mode=debug&edition=2021&gist=21cdaa3e90ffdd6a5ef2e06302afe03b
2022/04/15(金) 11:41:06.84ID:ZUiiq5D1
>>641
Rust特有の話については触れたくないんだろ
理解してないから
2022/04/15(金) 12:09:57.32ID:Y8j5AoVD
おじさん使いの人はいつもそうだよな
2022/04/15(金) 12:26:07.26ID:hAkRYyug
>>640
「クロージャ(ラムダ等)くらいはさすがに使ったことある」からといって「論理とメタ的な考え……ができる」ではないことは論理的に明らか。
全然論理的な考えができていない>640自身が反証になっているね。
2022/04/15(金) 12:58:35.38ID:b6lK2Xo1
>>643
lifetime mismatchのエラーが分かりにくければ、lifetimeを省略せずに明記して確認すればいい
2022/04/15(金) 13:07:01.81ID:FU35awjY
あと#![feature(nll)]でビルドしても分かるはず
2022/04/15(金) 13:08:53.72ID:OaJu93JV
>>646
むしろ論理とメタわからんプログラマーは言語関係なく向いてないっす
2022/04/15(金) 13:30:54.07ID:uTkCAN7R
理解の程度を0か1で考える人は底辺プログラマーに向いてる
651デフォルトの名無しさん
垢版 |
2022/04/15(金) 14:19:47.21ID:Xm9+ELTI
所有権でよくわからないって言えばさあ
fn asdf() -> &str{
let s = "jkl";
s
}
みたいにした時に、関数を抜ける際にstrのライフタイムが尽きちゃう訳じゃない
でも逆になぜ&strしかないのに、どうして関数を抜けるところまでstrのライフタイムが持つのか?そこら辺がよくわからねえな
&strを通じてstrを所有できているのであれば、&strをリターンできても良いような気もするのに・・・・どうなってんの?
2022/04/15(金) 15:21:50.13ID:k/yGxJzN
>>651
fn asdf() -> &str

fn asdf<'a>() ->&'a str
のようにlifetimeを省略した記法なんだけど、
この 'a は引数にも現れないし何の寿命に対応するか分からないからエラーになっちゃう

今回の文字列リテラルみたいにプログラム開始から終了まで存在するデータへの参照なら、
プログラム開始から終了までを意味する 'static を使うことはできる
fn asdf() -> &'static str

また以下のように引数に参照が登場する場合は、
戻り値の寿命は暗黙的に引数と同じだと見なされる
fn asdf(a: &str) -> &str

fn asdf<'a>(a: &'a str) -> &'a str
となるということ

この辺の仕組みは lifetime elision でググると情報出てくるよ
2022/04/15(金) 15:35:47.27ID:/A+hDicd
>>647
>>648
両方やってみて結局こうなったがまだよく分からん

https://play.rust-lang.org/?version=stable&;mode=debug&edition=2021&gist=aafabd8057a50f537f9ff410c03461d2

yが借用中にもかかわらずdropされたというふうに読めるけど、f(&mut y)が終わった時点で借用も終わってるから問題無いのでは?
でも試しにこの後yをどうこうするコード付け足してみると、どうも借用しっぱなしになってるっぽいエラーばっかり出るのよな
2022/04/15(金) 16:44:22.79ID:tw5ISWTc
>>651
&’static strが返されてるからだよ
リテラルはstatic扱いだと思っておけばいい

>>652
fn asdf<'a>() ->&'a strと書いても’>>651のケースはエラーにならないよ
2022/04/15(金) 17:24:32.32ID:k/yGxJzN
>>654
エラーにならないのか
その場合 'a は何に推論されるの?
2022/04/15(金) 17:51:47.56ID:VZ7u/ZvT
>>648
これさらにわかりやすくなるね
657デフォルトの名無しさん
垢版 |
2022/04/15(金) 19:50:10.79ID:rQzdCva+
ありがとう!
なんかちょっとズレたエラーメッセージだなと思っても、省略・推論されているなんて夢にも思わなかったから意味がわんなかったぜ!
658デフォルトの名無しさん
垢版 |
2022/04/16(土) 15:01:46.93ID:Tmn9GDW2
Rustって参照をベクターに持てる?
2022/04/16(土) 15:58:22.55ID:hx1ZC8lU
>>658
もてるよ
https://ideone.com/ZMCl2R
fn main() {
let a = 1;
let b = 2;
let v = vec![&a, &b, &a, &b];
println!("{:?}", &v);
}
660デフォルトの名無しさん
垢版 |
2022/04/16(土) 17:14:58.83ID:Tmn9GDW2
>>659
サンクス
2022/04/20(水) 18:37:23.24ID:3eLEi52G
Rust 入門者です。
全く実用的な意味はなく練習として符号無し整数を桁ごとに返すイテレータというものを考えていたのですが
同じ制約を重複して書くことになってしまい不格好な気がします。
https://ideone.com/qOmnhW
ベテランが華麗に書いたらどんな風になりますでしょうか。
それとも Rust ではこれで良いものなのでしょうか。
2022/04/20(水) 19:13:19.89ID:uLqNeO4/
>>661
traitの方の制約はいらないよ
2022/04/20(水) 22:38:14.51ID:3eLEi52G
>>662
ありがとうございます。
たしかにこのコードではトレイト Digits にスーパートレイトを付ける必要はないですね。

想定を後出しにして誠に申し訳ないのですが、これはライブラリ (クレート) としてまとめようとしているつもりでした。
ここに書かれていない未知の型にトレイト Digits を実装することがあり得るという意味です。

問題になるのは、 Digits のスーパートレイトを消してしまうとどんな型でも Digits の実装自体は出来てしまうということです。

// ↓ Digits にスーパートレイトを付けなければこう書くこと自体は出来てしまう。 この段階でエラーになって欲しい。
struct Foo {}
impl Digits for Foo {}

そしてメソッド digits を呼出すところでエラーになります。

let bar = Foo {};
for x in bar.digits() { // ← ここでエラーになる
println!("{}", x);
}

逆に言えば digits を呼出さなければエラーになりません。
どうせ使えないことがわかっているならトレイトの impl の段階でエラーであって然るべきだという判断が
重複する制約を書いた意図です。
メソッドがイテレータを返すなんていうのはよくあることだと思うので、
いちいち重複したことを書かかなくて済むような何かがあるんじゃないか……という想像から質問した次第です。
2022/04/20(水) 23:00:49.13ID:uLqNeO4/
>>663
そういう前提ならばこんな感じで impl の方の制約を T: Digits に変えるのはどうじゃろ
https://play.rust-lang.org/?version=stable&;mode=debug&edition=2021&gist=6bd0ab54e4cbd88ca2a0502f9e74315d

あと T::Error: std::fmt::Debug についてはどの trait の associated type に対する制約か分かり辛いから
<T as std::convert::TryInto<u8>>::Error: std::fmt::Debug,
としても良いかもね
2022/04/21(木) 00:02:58.32ID:9+GFB0OX
>>664
ありがとうございます。
なんてこった! こんな単純なことでよかったとは……。
2022/04/21(木) 13:57:26.69ID:Ast3pmta
数値にメソッドを生やすメリットが思いつかないからこれだけでいいんじゃない?

fn digits<T>(n: T) -> impl Iterator<Item=T>
where T: Clone + PartialEq + From<u8> + std::ops::DivAssign + std::ops::Rem<Output=T>
{
itertools::unfold(n, |n| (*n != T::from(0)).then(|| {
let rem = n.clone() % T::from(10);
*n /= T::from(10);
rem
}))
}

fn main() {
let foo: i64 = 9165731750932755204;
for x in digits(foo) {
println!("{x}");
}
}
2022/04/21(木) 14:14:33.93ID:Q5xBjMYc
実用上は関数で十分だろうけど、Rustって整数のプリミティブ型にもたくさんメソッドあるし、
メソッドを生やすのが流儀なのかな、って俺も思ってたけどどうなんやろ?
668663
垢版 |
2022/04/21(木) 14:30:15.62ID:9+GFB0OX
>>667
過剰にトレイトを作るなというのはドキュメントのどこかに書いてあったような気がする。
2022/04/21(木) 22:20:02.87ID:NWAfliAT
>>666の関数をメソッド化しようとしたら
traitやimplの中では関数はimpl Iteratorを返せないと怒られた
この制限は将来緩和される可能性ある?
implでなく返す型を具体化したらコンパイル通って動いた
traitとimplでwhereのところが冗長な気がするけど両方とも外せない?

trait Digits<T> {
fn digits(self) -> itertools::Unfold<T, fn(&mut T) -> Option<T>>
where T: Clone + PartialEq + From<u8> + std::ops::DivAssign + std::ops::Rem<Output=T>;
}
impl<T> Digits<T> for T {
fn digits(self: T) -> itertools::Unfold<T, fn(&mut T) -> Option<T>>
where T: Clone + PartialEq + From<u8> + std::ops::DivAssign + std::ops::Rem<Output=T>,
{
itertools::unfold(self, |n| (*n != T::from(0)).then(|| {
let rem = n.clone() % T::from(10);
*n /= T::from(10);
rem
}))
}
}

fn main() {
let foo: i64 = 9165731750932755204;
for x in foo.digits() {
println!("{x}");
}
}
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況