Rust part14
レス数が1000を超えています。これ以上書き込みはできません。
>>917
0からの列挙を型だけから導出できないといけない理由は何なのさ >>920
各型には上限値(とその有無)がありメモリサイズとトレードオフだからそこは気を使うよ
Rustではrelease modeだとC/C++と全く同じでオーバーフローしてもpanicは発生せずに数値がラップしうる
例えばi32で2147483647に1を足すと普通の足し算の+つまりadd()だと結果は-2147483648となる
これは数値計算だけでなく単なるカウンター利用に至るまで深刻な結果を招きうる
そのため足し算ならばchecked_add()等を必要に応じて使い分けることになる >>919
impl Foo for T where クソ長制約
vs
impl Foo for 具体的な型
という話なら多少興味もってもらえるだろうか
impl Foo for T は基本的に避けるべきだと思う >>922
Rust標準ライブラリでも他のクレートでもimpl Xxx for Tは山のようにある
それを避けるべきとの主張は全く意味不明 >>918
> impl FizzBuzz for u8, u16, ...
これもう構文として取り込んだらいいのにな
impl_fizzbuzz(u8, u16, ...)
こういうのを書く文化をいっそ言語の構文に格上げして >>923
impl Foo for T where 制約多数って例えばどのtraitの実装? >>924
そういう型別impl列挙は主に基本的なTraitにおいて行われており
それらを組み合わせてTrait境界とする上位のTraitでは列挙せずfor Tで済むようにRustは上手く設計されている >>800では対応できていたはずのf64が>>817でCheckedAdd追加したせいで対応できなくなってるよとか指摘すればいいの? >>926
上位のtraitって例えばどういうもの?
それは本当にtraitにすべきものなの?
traitにすることでどういうメリットがあるの? おまえらの議論が唐突すぎてよくわからない
今日の議論の発端となった今朝の書き込み>>884と元コード>>817及びそれ以降のレスには
impl … for Tなんて話は全く出てきていないぞ
ちなみにコードは以下のようになっている
> fn fizzbuzz<T>() -> impl Iterator<Item=FizzBuzzResult<T>>
> where T: Copy + PartialEq + CheckedAdd + Rem<Output=T> + TryFrom<usize>,
> { たぶんだけど>>922 >>924の話は
そのfn fizzbuzz<T>() where T: Boo + Foo + Wooとトレイト境界ジェネリックにしているのを禁止して
各々fn fizzbuzz_i8()、、、fn fizzbuzz_u128()を用意すべきという主張なんじゃないか >>929
>>800,804の話題を掘り起こしてしまった >>930
言葉足らずでスマソ>>924で言いたかったことは
macro_rules! impl_foo {略} // 中でimpl Foo for
impl_foo!(u8, u16, ...);
今はマクロ使って↑こうなりがちなものを
いつか言語として↓こうなったらなぁという話
impl Foo for u8, u16, ... {略}
お分かりのとおり非常にしょうもない些細な話w >>931
その>>800のコードは特に問題が無いのではないか
強いて言えばその後に出たいくつかの改善案を反映して
impl<T> FizzBuzz for T
where T: Clone + PartialEq + TryFrom<usize> + Rem<Output=T>
{
fn fizzbuzz(&self) -> FizzBuzzResult<&Self> {
let [zero, three, five] = [0, 3, 5]
.map(|n| T::try_from(n).ok().unwrap());
match (self.clone() % three == zero.clone(), self.clone() % five == zero) {
(true, true) => FizzBuzzResult::FizzBuzz,
(true, _) => FizzBuzzResult::Fizz,
(_, true) => FizzBuzzResult::Buzz,
_ => FizzBuzzResult::Num(self),
}
}
}
こんな感じ? >>919
だからこそ>>817がウンコードだと言われてるのに
わかんないかなぁ >>922
これはそうだな
impl Foo for Tはstdに入れるくらいのよっぽど汎用的なものでもなければ避けるべき >>933
それtraitにする意味ある?
>>935
FooExt もありだと思うが where T: Foo と制約はシンプルであるべき >>936
確かにextension traitは有りだな impl<T> _ for T where T: ... 形式のことを blanket implementation って言うんですね
cargo doc で型のページの下の方に出てくるのは知ってたけど、正確な定義は今知った >>936
元々の質問がi32など各整数にメソッドを増やしたいとの質問だったようだ
それで>>789からずっと
trait FizzBuzz {
fn fizzbuzz(&self) -> FizzBuzzResult<&Self>;
}
となっていてそれを前提に皆が話をしてる
ちなみにコードがスレへ貼られていないと検索しても出て来ずに不便だとわかったw >>939
>>804-806辺りで皆から指摘されてますやん >>940
そいつらは例えばイテレータメソッドを増やしたことすらない初心者かもな
Rustでメソッドを増やすにはトレイト定義が必須で欠かせない そもそもメソッド増やす必要ありましたか?
仮に方法だけ質問されたとしても、「やめとけ」と答えるのも回答のひとつですよ な、複オジ相手にしても時間の無駄だっただろ?
いい加減学習しようぜ >>942
メソッドを増やすべき状況は多々あります
既に出ているイテレータメソッド等もその一例です
そして今回のFizzBuzzはあくまでも例ということですからFizzBuzz自体をメソッドにするべきか否かの議論はどうでもよく無意味でしょう
メソッド化を実現できること自体の方が本質にみえます >>942
最初の質問者 (>>781) はまだ Rust の基礎を学んでいる途中なのだというのが前提にある。
FizzBuzz についての質問であったとしても別に FizzBuzz を書きたいわけではなかろう。
Rust を学ぶ題材として試しに FizzBuzz を取り上げてるだけだ。
だから「FizzBuzz では」やめとけというだけでは回答として不十分。
「『必要であれば』書き方はこんな感じだよ」という形で話を膨らませるのはごく普通の対応に思える。
Rust 自体に習熟してないのにその上での設計の良し悪しなんてこの段階で論じるようなことでもない。 >>942の人は単なる反抗期なんじゃね
書き込みを見ると何でも反対してる
それでいてCheckedAddを使わずにMAXを使え!など提案が的外れ >>943
すみませんでした
しばらくROMります >>941,944,946
これが複オジ論法
技術的な議論は無理 >>933
zeroのclone()は不要
他はOK
それならBigIntでも動作する 避けるべきというアンチパターンが出来ている時点で欠陥言語、 where T: Fooなどと書けるがRustは決してシンプルじゃない Rustの目標はシステムプログラミング言語だから、C/C++に比べてマシならおーけー >>951
避けるべきと言ってる人の独りよがり
根拠も示さず個人的に毛嫌いしてるだけ ,―彡 ⌒ ミ―、
〈 〈| ´ん` |〉 〉
\ ヽ _ / /
/ /みんなで
/ /ホモセックス 反対!君とうんこ!君は代案コードを出さない(出せない)から無視しとけ >>948
あーなんか既視感あるとおもったら菅話法だw >>933
Rustはそうやってシンプルに安全に多型に対応できるところがいいよな >>945
なるほどこれがオナニー指向の思考回路か C言語でプログラミング入門した口だけどRustみたいな関数型言語わからなくて困ってる
例えばOCamlみたいな型推論前提で書かれているコードはどの変数がなんの型になるのかわからなくてつらい思いしている
関数型言語のプログラマはみんな自分で型を推論しながらプログラミングしてるんですか? >>959
むしろ型推論してくれるからプログラマーは楽
ただしどこかで歯止めがある方が安全安心確実だからRustでは関数の入出力のみ明示する
それも例えば>>929の返り値のように型そのものではなく抽象的にトレイト名で記述も可能
もしある値(式)の型を知りたかったらプログラムで表示も可能だけど一番簡単なのは
let a: i32 = 値;
とデタラメな型名i32を宣言してやるとコンパイラがエラーとして正しい型名を教えてくれる 基本的にはIDEに型を教えてもらってたけど、慣れてくると自分でどんどん型がわかるようになる >>959
VSCode+rust-analyzerなら変数の型やメソッドチェーンの途中の型が全部出るよ >>959
どの型に確定するのか把握しなければ使えないのだとしたら、その関数の設計が悪い。
まあ程度問題ではあるけど……。 >>960,962,963
ほーんなるほど
今ocaml勉強しているんだけど
if式のthen節とelse節の式の型は両方一致するとか、
match式においてもすべての分岐の式の型は一致するといかいったことを把握していってるわ
それ取っ掛かりにして関数全体の型把握するようにしたい
あと分岐の片方でラムダ抽象置いて束縛変数導入したらばもう一方の分岐ではconst関数に第一引数適用したの置いて分岐全体の型を合わせるとかいうテクニックとかも他人のソースから学んだンゴ
でも他の言語に比べてocamlのソースはなかなか転がっていない印象を受けるんごねえ
あとSKIコンビネータとかの型も式から推測するのもややこしくて難しいンゴねえ rust-analyzerっていえばさ
俺のVSCodeをYoutuberのと見比べると、構文間違えなどのアンダーラインが出現・消滅するタイミングが違うんだよね
Youtuberらのがリアルタイムで線が引かれているのに対して、俺のは保存しないと線が引かれたり消えたりしない・・・・しかも、俺の手元ではMacでもWindowsでも一緒の症状・・・・
誰かエスパーさんいたら解決策を教えて!!! >>965
自動セーブにする必要があるとかじゃないの? >>967
審査無しでユーザーが好きに登録できるパッケージマネージャにはよくありがちなことだな
パスワードが盗まれて正当なパッケージが置き換えられたわけじゃないからまだまし
Firefoxの拡張の中には第三者が権利を正当な形で引き継いだその後の更新でマルウェア化しているものがあるって報告があるくらいだし Rustで書くと依存crateが100オーバーになるのも珍しくないから
アプリ開発者がリリース単位で常時全部チェックするのは手間がかかりすぎる
全チェックじゃなければcargo crevとかで閾値決めとくとかしかないよね >>972
マルウェアというよりアクセス履歴を収集するようになったってやつでしょ >>824
ホントだ
127の次でpanicした
(1_i8..).for_each(|n| print!("{n} "));
release modeではpanicではなく127の次が-128になって永久循環 適当に作れば溢れる前に止まる
fn countup<T>(start: T) -> impl Iterator<Item=T>
where T: Clone + TryFrom<usize> + num::CheckedAdd,
{
let one = T::try_from(1).ok().unwrap();
itertools::unfold((start, true), move |(n, is_first)| {
if *is_first {
*is_first = false;
Some(n.clone())
} else {
n.checked_add(&one)
.map(|new| {
*n = new.clone();
new
})
}
})
}
fn main() {
countup(1_i8).for_each(|n| print!("{n} "));
} >>975
1_i8..=i8::MAXにすればいいだけ
型のMAX値までRangeFromでイテレートするなんて処理は現実のプログラムでは必要ないから >>977
それは数値型にしか使えないので>>976かな >>976は悪いお手本が盛り沢山
真似しちゃダメだぞ Rangeをpanicしないように扱う方法ないの?
CheckedRangeみたいなやつとか >>980
Rangeはオーバーフローしないよね?
RangeFromでオーバーフローして困るなら上限を指定しないと
スレ立てもヨロ >>982
もっと厳しそうなStringで>>976をやってみた
Zの個数で数を表すZ
#[derive(Debug,Clone)]
struct Z(String);
impl std::fmt::Display for Z {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<usize> for Z {
fn from(n: usize) -> Self {
Z("Z".repeat(n))
}
}
impl std::ops::Add for Z {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Z(self.0.clone() + &(rhs.0))
}
}
impl num::CheckedAdd for Z {
fn checked_add(&self, rhs: &Self) -> Option<Self> {
Some(Z(self.0.clone() + &(rhs.0)))
}
}
fn main() {
countup(Z::from(1)).for_each(|n| println!("{n}"));
}
ちゃんと動作してZの数が増えて行くんだな >>984
それは独自の型であってStringではないよ
上限までイテレートするのに上限が無い型を実装して何がしたいのかわからないが
countup(Z::from(usize::MAX))とかで確認した? >>985
Rustのorphan ruleを知らないのかよ
独自の型に対してしか既存traitを実装できない規則なのでそこは独自の型で正しい >>986
全くもって間違ってるよ
アプローチが間違ってるから>>976や>>984みたいなものしかできない >>984
“Z”を繰り返したいだけなら
(1..100).map(|n| “Z”.repeat(n))でいいのに
新しい型を作って4つも5つもトレイト実装することに何かメリットあるの? >>988
抽象的な考えが出来ない人なのかな
そういうのはあくまでも例であってZを表示したいわけではないことくらい分かるでしょ >>976
上限のある型を作ってトレイト境界を満たしてやるとちゃんと上限で止まるんだな
#[derive(Debug,Clone)]
struct FiveBits(usize);
impl FiveBits {
fn make(n: usize) -> Option<FiveBits> {
(n >> 5 == 0).then(|| FiveBits(n))
}
}
impl TryFrom<usize> for FiveBits {
type Error = &'static str;
fn try_from(n: usize) -> Result<Self, Self::Error> {
FiveBits::make(n).ok_or("overflow")
}
}
impl std::ops::Add for FiveBits {
type Output = Self;
fn add(self, rhs: Self) -> Self {
FiveBits::make(self.0 + rhs.0).unwrap()
}
}
impl num::CheckedAdd for FiveBits {
fn checked_add(&self, rhs: &Self) -> Option<Self> {
FiveBits::make(self.0 + rhs.0)
}
}
impl std::fmt::Display for FiveBits {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
} >>980
Rangeは上限ありだから大丈夫
RangeFromならば>>976みたいなのでいいんじゃない? >>985
それは君が思い込みで勘違いをしている
>>976のイテレータを見るとchecked_addが使われているため
その型に上限が有れば上限で止まるから君の言うとおり
しかしその型に上限が無ければ(リソースの有る限り)無限に進むことになる >>789
> fn fizzbuzz(&self) -> FizzBuzzResult<&Self> {
その関数を使わせてもらってイテレータにしようと思ったら
参照を返しているために非Copy型に対して上手くいかなくて手詰まってしまった このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 90日 14時間 44分 13秒 レス数が1000を超えています。これ以上書き込みはできません。