Rust part27

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
垢版 |
2024/12/02(月) 22:32:50.31ID:D+1pIyvG
公式
https://www.rust-lang.org/
https://blog.rust-lang.org/
https://github.com/rust-lang/rust

公式ドキュメント
https://www.rust-lang.org/learn

Web上の実行環境
https://play.rust-lang.org

※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/

※次スレは原則>>980が立てること

前スレ
Rust part26
https://mevius.5ch.net/test/read.cgi/tech/1726838318/

ワッチョイスレ
プログラミング言語 Rust 4【ワッチョイ】
https://mevius.5ch.net/test/read.cgi/tech/1514107621/
2025/03/03(月) 01:43:43.47ID:lMbQDSSk
gopls implementationとかで確認すればいいよ
341デフォルトの名無しさん
垢版 |
2025/03/03(月) 03:55:57.34ID:US4xw5vs
今どき珍しい真面目なスレッドだな
2025/03/03(月) 04:54:41.57ID:CkLabMrP
>>330
静的ダックタイピングは明示的インターフェイスでも成り立つよ。>336で言うならテンプレートとコンセプトみたいにテンプレート引数の要件を明示するやり方。

>330の言い方なら、
共通する構造&機能がある時に
・共通することを型としてあらかじめ宣言するか
・共通部分を使う時に判別するか
の違いですな。
後者は共通する構造&機能の決定を実際に使用する時まで遅らせることができるので、型の設計時点で決めなくてはならない前者よりも設計の自由度が増す。

Adapterパターンのサポートが充実していれば問題を緩和できるけど、Rustて充実してたっけ?
2025/03/03(月) 06:07:05.65ID:YJglMSFw
Rustは各型で共通事項をあらかじめ宣言する必要がなく
共通する構造&機能の決定を実際に使用する時まで遅らせて
それらが決まってから後から実装すればよいため
設計の自由度が高いね
2025/03/03(月) 07:42:47.63ID:FotMwNUg
>>343
あれ?どうやるんだっけ?
345デフォルトの名無しさん
垢版 |
2025/03/03(月) 10:32:52.62ID:CIgoBgkV
他人の書いたコードをインタフェースで抽象化したいときにGoのinterfaceは便利だけど
全て自分で管理する場合は明示的に宣伝した方がいいから選べるようにしてほしい

Javaの普通のinterfaceに加えてGoのinterface同時に使える言語が欲しい
346デフォルトの名無しさん
垢版 |
2025/03/03(月) 10:43:32.37ID:wkIAEgPa
>>341
少し考えれば理由はわかるはず
347デフォルトの名無しさん
垢版 |
2025/03/03(月) 10:47:29.58ID:US4xw5vs
>>346
お?上から来たな
2025/03/03(月) 19:22:07.10ID:niTL8qrF
>>345
interfaceに関して欲しい機能はRustのトレイト境界の機能だろ
Javaには類似の境界型パラメータがあるが単相化しないため役に立たない
2025/03/03(月) 19:49:07.58ID:SsAcHPN0
>>343
Rustで共通事項をあらかじめ宣言しないで、共通する構造&機能を統一的に使うのってどうすればいいの?

Rustの型システムを考えると、(既存のコードを変更することなく) 共通する構造&機能を新たに宣言して統一的に扱える、ということだよね?
2025/03/03(月) 19:56:00.40ID:niTL8qrF
リファクタリングをするのに既存のコードを変えないとか矛盾していて意味がわからん
後から共通メソッドをトレイト化すればいいだけだろ
それで困る人はいない
2025/03/03(月) 21:42:58.25ID:CkLabMrP
>>350
例えば標準ライブラリの型との共通部分を統一的に扱いたい場合、標準コードをリファクタリングして新しい共通Traitを切り出すのかしらん?
2025/03/03(月) 22:28:07.80ID:T1gSmlwj
Rustでコーディングしたことないお客さんが来てるのか?
標準ライブラリのコード自体を書き換えなんてせずとも普通に行われていることだぞ
2025/03/03(月) 22:56:04.92ID:trSew6xi
>>349
>>343が言ってるのはstructの定義時にそのstructがどのtraitを実装するかを(あらかじめ)宣言する必要はなく後から必要になった時にtraitの宣言及び実装をすればいいというだけの話

わざとずらしたことを書いてるから噛み合ってないんだよね
2025/03/03(月) 23:07:24.80ID:trSew6xi
既に存在する共通する構造&機能をポリモーフィックに扱いたい時にGoなら必要なのはインターフェース宣言だけ
既存のインターフェースに合致するものなら新しく宣言する必要もなくそのまま扱える

一方Rustの場合は新しいインターフェースを宣言して既存の構造体に対する新しいインターフェース用の実装をそれぞれ追加で書かない限りは使えない
それで済めばまだいい方で既存のインターフェースに適合させなければいけない場合は既存の構造体をラップする新しい構造体とその実装を逐一全部書いた上にインターフェースに対する実装も別途追加で書かないダメ

特に後者の手間は雪だるま式に膨れ上がるからライブラリのように他人に使わせるコードを書く場合は型の設計時点というより外部APIの設計時点で何を共通の構造&機能として使えるようにするか決めておく必要がある
2025/03/03(月) 23:24:45.25ID:uMOb2Eig
> 既存のインターフェースに合致するものなら新しく宣言する必要もなくそのまま扱える

無茶苦茶だな
そんな意図しない全ての型に自動適用される危険な言語は使いたくないわ

Rustは明示的にimplしたものだけに適用されるから安全で使い勝手が良い
2025/03/03(月) 23:29:41.09ID:uMOb2Eig
> 一方Rustの場合は新しいインターフェースを宣言して既存の構造体に対する新しいインターフェース用の実装をそれぞれ追加で書かない限りは使えない

そんなことはない
既にimpl Tにあるのだからimpl Trait for Tへ移動させるだけだぞ

> それで済めばまだいい方で既存のインターフェースに適合させなければいけない場合は既存の構造体をラップする新しい構造体とその実装を逐一全部書いた上にインターフェースに対する実装も別途追加で書かないダメ

そんなことはない
既存の構造体にそのままtraitメソッドを増やせる
2025/03/03(月) 23:46:24.87ID:T1gSmlwj
Rustでコーディングしたことないお客さんがこのRustスレでRust叩きとは完全に荒らしだ
358デフォルトの名無しさん
垢版 |
2025/03/03(月) 23:56:56.53ID:BZGxSOwK
外部クレートで定義されたトレイトを別の外部クレートの型に対して実装するときはラップが必要じゃない?
要素1つのタプル構造体 (いわゆる new type) で済むような話だけど
インターフェースといってるあたり微妙にズレてる感はあるけど、「ラップする必要がある」という点自体は間違ってない
2025/03/04(火) 00:10:16.92ID:PYBK8h/l
>>358
そんな話は誰もしていないよ
今話されているのはこれ

>既に存在する共通する構造&機能を
>新しいインターフェース宣言

複数の型に共通事項が出てきたから
新たなトレイトを作って宣言する話が行われてる
ラップは不要
2025/03/04(火) 00:26:54.32ID:ZIAXnU+S
自分の管轄外の型に対して、自分の管轄外のトレイトを実装することだけは、安全のため禁止されているので、自分の型にするためのラップが必要
そんな特殊な例外的ケースを除けばラップはもちろん不要
2025/03/04(火) 01:25:48.23ID:JpOggS8o
最初からクレート境界を前提とした文脈だろ >>298
文脈読めよ
2025/03/04(火) 01:53:29.12ID:s9xD5Zkr
インターフェイス vs. ダックタイピング

ダックタイピングはインターフェイス名がないため可読性が著しく低い
インターフェイス名を使った制約も指定できない
必ずインターフェイス機能を使うべし
2025/03/04(火) 02:35:55.33ID:VOLcqrY4
>>362
こういう簡潔なまとめ助かる
2025/03/04(火) 06:51:13.78ID:r27xQ0ge
ダックタイピングは、意味が異なっていても、見かけの構造さえ同じなら、同一視してしまう問題もある
つまりうっかり間違えて用いても、エラーを検出できないため、安全性で劣る。

その見かけの構造さえも、複数の構造を含む場合など、
この型はどのダックタイピングで用いられているのか、読み手が認識するのに時間がかかってしまう。

これらの問題は、各型において、どのダックタイピングに用いられているのかの宣言がないことに起因している。
一方で、interfaceは「各型でどのinterfaceを用いているのか」の宣言があるため、どちらの問題も生じない。
2025/03/04(火) 09:45:00.92ID:murVybZ/
>>327 奇遇ですね私もです
366デフォルトの名無しさん
垢版 |
2025/03/04(火) 09:47:17.60ID:murVybZ/
>>333
実行前(コンパイル時など)に問題が表面化することと
実行後に問題が表面化することの違いは果てしなく大きい
2025/03/04(火) 09:50:16.00ID:murVybZ/
>>339
ほんそれ
2025/03/04(火) 09:52:06.99ID:murVybZ/
>>342
だからRustは清書用って言われるんだよ
2025/03/04(火) 09:55:52.32ID:murVybZ/
>>351-352
type alias でほぼ何でもありな状態に出来るけど
他人のcrateとさらに他人のcrateを混ぜてると詰む
2025/03/04(火) 09:57:24.96ID:murVybZ/
>>353
君こそコーディングしたことないだろ
2025/03/04(火) 10:00:12.78ID:murVybZ/
ああ 353 は引用なのか?
354 と 353 が同一人物ならきもいが
354 の言ってることが実情
372デフォルトの名無しさん
垢版 |
2025/03/04(火) 10:02:37.01ID:murVybZ/
>>356
↑こういうのが混乱を招くからやめれ
2025/03/04(火) 10:09:07.10ID:murVybZ/
>>359-360
struct に限ってはそうだね
2025/03/04(火) 11:30:33.83ID:CoDTmeUS
>>342
Rustでは最初から共通部分があることを意識する必要がなく
そのような場合でも設計の自由度が高い
共通部分が生じたことに後から気付いた時点でそのためのトレイトを後から宣言すればよい
2025/03/04(火) 11:34:47.54ID:CoDTmeUS
>>354
Rustならばラップは必要なく、トレイト宣言をしてトレイト側へメソッドを移動するだけで簡単に済む
impl Foo {
 fn method(&self, ...
}
impl Bar {
 fn method(&self, ...
}
と複数の型に共通メソッドがあり、それをトレイトで共通に扱えるようにしたければ

// トレイト宣言
trait TraitName {
 fn method(&self, ...
}
// トレイト実装
impl TraitName for Foo {
 fn method(&self, ...
}
impl TraitName for Bar {
 fn method(&self, ...
}
つまり「impl Foo」から
「impl TraitName for Foo」へ移すだけで済む
今回の例なら差分タイプ量は「TraitName for」のみ
376デフォルトの名無しさん
垢版 |
2025/03/04(火) 12:03:00.52ID:murVybZ/
struct のときだけね
2025/03/04(火) 12:04:58.27ID:CoDTmeUS
>>376
enumでも他でも同じ
378デフォルトの名無しさん
垢版 |
2025/03/04(火) 12:18:25.90ID:murVybZ/
フーン(ニヤニヤ)
2025/03/04(火) 12:40:56.52ID:uaFJKO3n
伸びてると思ったら複オジの類友が増えただけだったorz
2025/03/04(火) 12:45:41.91ID:DDDjLfi5
>>376
structに限らず全ての型に対してトレイト実装によりメソッドを増やせるよ
2025/03/04(火) 12:58:42.56ID:WqCDnV/I
&str(実質&[u8]でもVec<u8>でも)の末尾に
ゴミで良いから毎回必ず'\0'付ける仕様にしといて欲しかった
2025/03/04(火) 13:19:59.57ID:813wXAHn
>>381
'\0'に限らず任意の値を終端として型を定義できるZigの勝利だね
383デフォルトの名無しさん
垢版 |
2025/03/04(火) 13:44:40.50ID:QtwoMD6j
やっぱ崩れたかw
346みたいな偉そうな奴がいるとなw
2025/03/04(火) 13:53:15.88ID:aSLD1MTT
死んだスレが生き返ることなどない
2025/03/04(火) 15:55:00.59ID:UUqFoJ1U
>>381
必要な時だけ付けりゃいいじゃん
不要なものを常時付けとけとか頭おかしい
2025/03/04(火) 16:14:05.76ID:Xo2DP/vf
異なる方式を混ぜ合わせると両方を協調するのにミスが入りやすい。
ゼロ終端方式とファットポインタ方式に常に矛盾が生じないように維持するくらいなら必要なときに変換するほうがマシ。
2025/03/04(火) 16:16:40.93ID:HZGad4Nn
>>375
>つまり「impl Foo」から
>「impl TraitName for Foo」へ移すだけで済む
>今回の例なら差分タイプ量は「TraitName for」のみ
フィボナッチみたいなトイコードしか書いたことがないと
こんな意味のない破壊的な変更を無自覚に書いてしまうんだな
2025/03/04(火) 16:28:38.12ID:c62Mny0R
>>381
"abc"の部分文字列"ab"を参照する時に元の文字列が"ab\0"になるけどいい?
2025/03/04(火) 17:42:39.60ID:uxSCDJ2e
>>381
&strはStringや(別の)strの任意の部分文字列を参照する型
もし末尾に'\0'を付加すると次の文字を'\0'で上書きするため原理的に不可能
Rustで'\0'終端文字列はCStr/CStringを使う
リテラルならc"ABCDE"

ちなみにC/C++で部分文字列を扱うと
同じ問題が起きるため別領域へコピーして末尾'\0'を付加する
さらに途中に'\0'を置くと千切れる問題や
長さを知るために'\0'まで要走査の問題があるので
Rustのstr/Stringでは'\0'終端文字列としていない
2025/03/04(火) 17:44:45.66ID:uxSCDJ2e
>>387
新たなトレイトを作ってメソッドを移しても破壊的な変更にならない
もちろん移すだけでは意味はないが
使う側でそのトレイト境界を用いてコードの共通化が可能となるため普通に行なわれる
2025/03/04(火) 18:39:12.83ID:gw3gBjaL
>>389
いつの時代のC++だよw
2025/03/04(火) 23:48:22.54ID:qtalPCL7
>>391
昔も今もC + +のs t r i n g関数s u b s t r (開始位置, サイズ)は別の領域を確保してコピーだよ
\0終端するためにコピーは避けられないね

ちなみにライブラリ実装依存だろうけど
毎回ヒープ領域確保はコストが大きすぎるため
結果が15文字までならば静的に各16バイトの領域を事前に持っていてそこを使って頑張っていたりはする
でもそこへのコピーは避けられないね
2025/03/05(水) 00:13:26.12ID:cALyDE8e
>>390
うわぇー
なんでそんな嘘を吐くの?
もしかして破壊的変更の意味を知らない?
2025/03/05(水) 00:15:45.55ID:+YosNdhq
>>391
C++ の中だけでやるなら今は range を中心にライブラリが編成されてるから文字列の一部を取り出すのにコピーは必要ないしゼロ終端も不要だが、ここでは (古いライブラリなり API なりの都合で) ゼロ終端が必要になったときはという前提の話をしてるんだぞ。
外の世界は言語の都合に合わせて勝手に変わってくれたりはしない。
モダンな C++ を使っていても外と繋がる境界では外の都合に合わせなきゃしょうがないんだ。
2025/03/05(水) 01:23:27.50ID:zAVGaXEW
>>394
Rustの中だけでやるなら文字列の一部を取り出すのにコピーは必要ないしゼロ終端も不要だが、ここでは (古いライブラリなり API なりの都合で) ゼロ終端が必要になったときはという前提の話をしてるんだぞ。
外の世界は言語の都合に合わせて勝手に変わってくれたりはしない。
モダンなRustを使っていても外と繋がる境界では外の都合に合わせなきゃしょうがないんだ。

君の言う前提に沿えば>>389の比較は無意味
2025/03/05(水) 01:31:23.03ID:+YosNdhq
>>395
「いつの時代の C++ だよ」に対していつの時代でもそうだよと言ってるだけ。
>>389 には興味ない。
2025/03/05(水) 01:45:32.35ID:+YosNdhq
>>395
あらためて >>389 を見たら「ゼロ終端にするにはコピーが必要なのは同じだ (型の整理の仕方は違っても)」というのが趣旨だから結論が同じなのは意図どおりだろ。
2025/03/05(水) 03:17:39.16ID:nw/EeQ+y
>>389
CString::new(string)で0終端してくれて
c"ABCDE"は最初から0終端されてて便利だね

// 固定文字列は c"..." リテラルで作成
let c1 = c"ABCDE"; // &CStr型
// 文字列を組み立てる場合はStringで作成しておいて
let s = ('A'..='E').collect::<String>();
// そのStringを消費して0終端してくれる (途中に0があるとError)
let c2 = CString::new(s).unwrap();
// 左右どちらも &CStr型の c"ABCDE" で一致
assert_eq!(c1, &*c2);
2025/03/05(水) 10:19:35.16ID:wPTO1w2Q
このスレいつからワッチョイとかIDとか無くなった?
2025/03/05(水) 11:21:05.48ID:yWF1u2Fm
隔離スレにそんなもん必要ねえよ
2025/03/05(水) 12:18:55.35ID:8D9MhhW+
ワッチョイとかIDがあると自演するのに不便だからいらない
2025/03/05(水) 12:31:30.46ID:wPTO1w2Q
本スレどこ?
2025/03/05(水) 12:35:55.74ID:yWF1u2Fm
まともに他人の意見を尊重できる人たちが集まり議論が行われればそこが本スレになるだろうが、期待するだけ無駄じゃろ
2025/03/05(水) 22:19:07.11ID:GGwXatao
>>398
自分で'\0'プッシュすればええやんと以前は思っていたけど
ミスがないことを型システムに保証してもらえる安心感
2025/03/05(水) 23:13:15.92ID:tlB2HjRS
>>402
DかZにおいで
2025/03/06(木) 07:37:15.29ID:B42CPAD4
自分でNULL終端しようとする老害は
安全を保証する型システムと相性悪い
2025/03/06(木) 15:59:09.42ID:WqcKZUUD
[c_char]が[u8]だと思ってたら[i8]だったでごじゃる
2025/03/06(木) 17:21:49.66ID:hP34p9/Z
c_charは処理系依存っぽいからu8かi8に決め打ちするならc_ucharかc_scharにキャストした方がいい
ターゲット変更した時にコンパイラに文句言われる可能性がある
2025/03/06(木) 18:39:39.08ID:c+X1ur2G
\0終端じゃないと困るってcやc++から来た人だろ…
老害っているんだな
2025/03/06(木) 19:04:31.26ID:lbAGNheW
>>409
OS の要求ならしょうがないだろ……
適当なラッパー作るにしてもそのラッパーの中ではゼロ終端にしないわけにはいかん。
2025/03/06(木) 23:08:05.29ID:/xPeDHQy
>>398
あとはCString/CStrからの変換だな
&[u8]として扱えるのは当然として

// CStringを消費して Stringとして扱う (非UTF8だとError)
let c = CString::new([b'A', b'B', b'C', b'D', b'E']).unwrap();
assert_eq!(c.into_string().unwrap(), String::from("ABCDE"));

// &Cstrを &strとして扱う (非UTF8だとError)
assert_eq!(c"ABCDE".to_str().unwrap(), "ABCDE");

// &Cstrを Cow<str> にする
// UTF8なら &strとして扱い Cow::Borrowed(&str)型
let cow = c"ABCDE".to_string_lossy();
assert_eq!(cow, Cow::<str>::Borrowed("ABCDE"));
// 非UTF8部分があると U+FFFD置換Stringにして Cow::Owned(String)型
let cow = c"AB\xccDE".to_string_lossy();
assert_eq!(cow, Cow::<str>::Owned(String::from("AB\u{FFFD}DE")));

いずれも'\0'の存在は気にしなくていい
2025/03/07(金) 23:55:18.15ID:nJW2jcZy
&selfで読み取り参照のまま、別の型の読み取り参照に読み替えるのはもちろん、
selfで消費してしまい、確保メモリをそのまま活用して、別の型に読み替えるのが効率ええんやな
2025/03/08(土) 09:38:56.99ID:y8OZgzU7
>> http://mevius.5ch.net/test/read.cgi/tech/1708677472/784

Ruby (が採用している CSI 方式) での文字列オブジェクトはそれぞれどの文字コードであるかの情報を持っていて処理系は各文字コードの処理方法を知っている。
つまり文字列を扱うあらゆる箇所で様々な文字コードごとの処理をやってる。
それが先進的か?
文字コードが統一できない世界でも「なんとかする」方法だろ。

内部的には統一した文字コードで扱い、様々な文字コードを扱いたければ入出力の段階で変換するというのが Rust 的なスタイルを含む現代的なプログラムが目指すところで、そのために Unicode はあるゆる文字コードから「変換可能であること」を指向してる。
とはいえ、これが先進的と言えるわけでもなく総合的に考えて現代の事情に合うやり方ってだけだ。

様々な文字コードの変なところも含めて Unicode に取り込んでいるのは既存のテキストのデータを (情報を失うことなく) 移行できなきゃ Unicode に統一されていかないからで、同じ駄目なら統一されていないことによる駄目さより統一されてる駄目さのほうがかなりマシという価値観による。
いろんな駄目さに個別に対処するのではなくデカい駄目に皆で立ち向かう。

人間の言語が数千年・数万年の歴史的経緯の積み重ねなので文字も駄目だし文字コードも駄目。
根本的に駄目なものはどう扱ったって駄目。
綺麗なやり方で扱わないのは綺麗なやり方が存在しないから。。
2025/03/08(土) 17:22:21.85ID:O70yvsau
AIで3行程度にまとめてから書き込んてくれる?
2025/03/08(土) 22:27:54.11ID:EzMMiepo
ネットもファイルもUTF-8で統一しちゃうのが吉
外部のcharset=Shift_JISとか扱わないといけない分だけencoding_rs _io
416デフォルトの名無しさん
垢版 |
2025/03/10(月) 03:27:00.75ID:SacQDf18
>>356
>>375
>既にimpl Tにあるのだからimpl Trait for Tへ移動させるだけだぞ

pub 付いてると知名的なので doubt
2025/03/10(月) 08:58:57.66ID:CNm9iAF0
crateとかdocsの事考えるとそんな単純な話じゃないんだよ
実践的なコード描いてない人か
2025/03/10(月) 12:17:05.04ID:BVl3qR6K
歴史的にマクロ=悪の固定観念もってるプログラマも多い気がするから
macro_rules!()はtemplate!()に改名した方がいいかもしれんね
impl Traitとかマクロ使わないと面倒な場合が多い
2025/03/11(火) 15:16:53.15ID:mrtJh8pq
Rustってfor_eachのclosureのなかでbreak出来ないのです
2025/03/11(火) 16:23:47.17ID:GvJGmymX
>>418
名前は Scheme の syntax-rules から持ってきたんだと思う。
2025/03/11(火) 16:37:58.97ID:FiOBTiHo
>>419
map_whileやtake_whileか
try_for_eachやtry_foldを使えば?
ControlFlowを使って自分で作る方法もある
2025/03/11(火) 19:10:27.26ID:iBVYkGzp
>>419
クロージャは(変数をキャプチャできる)関数の一種なのでbreakなんて概念はない
for_eachはクロージャを引数に取る高階関数なのでbreakなんて概念はない
次々とやってくる「全ての各エレメント」に対して何度もそのクロージャを呼び出すだけなのでクロージャで早期returnしようとしても全てのエレメントに対して処理される
やりたいことはおそらく次々とやってくるエレメントの途中で処理を終えたいのだろうからfor_eachではなく以下のイテレーターメソッドを使う
2025/03/11(火) 19:12:23.50ID:iBVYkGzp
>>419
中断条件を分離できるならばイテレータを返してくれる(そして他のイテレータメソッドを繋げられる)以下を使うのがベター
take(n) 最初のn個だけ
while_some() OptionがSomeの間だけ
take_while(f) fが真の間だけ
 その後に続きを漏れなく使いたいときは
  take_while_ref_inclusive(f)
  take_while_ref(f)
  peeking_take_while(f)
map_while(f) 変換しながらfがSomeの間だけ
scan(init_state, f) 状態を持ちながら変換しながらfがSomeの間だけ

いきなり結果を(ResultやOptionやControlFlowで)返したいならば
try_for_each(f) fが中断(ErrorやNoneやBreak)になったら終えてそれを返す 中断なければ()を返す
try_fold(init_state, f) 状態を持ちながら同上 中断なければ状態を返す
try_collect() iterとitertoolsで仕様が異なりiter版はnightlyのみだけど 中断になるまでをcollect
2025/03/11(火) 21:21:23.37ID:jytsrQer
要点をまとめる力って大事だな
2025/03/12(水) 00:42:42.49ID:XRphkku6
クロージャが関数の一種なのか関数がクロージャの一種なのかそれが問題だ
2025/03/12(水) 02:15:27.24ID:ck/kStOw
大雑把な説明としては、
クロージャは(キャプチャがある)関数の一種、
関数は(キャプチャのない)クロージャの一種、
と言っても構わないが、
実際には、
Fnで使えるのはsafeなfnのみ、
fnにコアースできるのはキャプチャのないFnのみ、
といった関係。
2025/03/12(水) 12:58:04.29ID:7dQQHGES
クロージャと言えばFn(&mut T) -> ()みたいな定義が許容されてるのはなんでなの?
間違った使い方をすればownershipルールに違反してエラーにはなるだろうけどFnMut(&mut T)->()にするよう弾いたほうがよくない?
2025/03/12(水) 13:35:41.11ID:aNDBBqWo
ここ観るのが早い
https://qiita.com/lo48576/items/34887794c146042aebf1
2025/03/12(水) 16:12:44.05ID:FLZx408U
試しに見てみたがリファレンスと同じ情報の劣化版なので見る価値なし(個人の感想です)

>try_for_each(): Iterator<T> -> (T -> Try<B=()>) -> Try<B=()>
>失敗するかもしれない関数について for_each 的な操作を行う関数。
>これといって特記すべきこともないが、今まで for で書いていたものがシンプルにできる、ありがたい関数である。
>もし成功時にも何らかの意味ある値を返したいのであれば、 try_fold を使うべきである。

例えばtry_for_eachの最後の行の解説とか
ツッコミどころが盛り沢山
2025/03/12(水) 18:16:35.74ID:ck/kStOw
>>427
クロージャの引数は、毎回変わるのだから常に何をしても自由であり、引数を消費してしまおうが、可変参照があって参照先を書き換えようが自由。
クロージャで制限がありうるのはキャプチャした値のみ。

Fnはキャプチャした値がある時に、それを読み取り参照しようが自由だが、書き換えたり消費したりはできないという意味。
FnMutはキャプチャした値を読み取り参照しようが書き換えようが自由だが、消費してはいけないという意味。
FnOnceはキャプチャした値を消費しようが書き換えようが参照しようが自由という意味。
キャプチャ値を消費をしてもしなくても自由ということは、2回以上の実行は不可で、そのクロージャの実行は1回だけという意味、だからFnOnceという名前。

トレイト間の関係は「Fn: FnMut」かつ「FnMut: FnOnce」、つまりFnOnceは他の最上位のスーパートレイト。
集合で見ると、FnOnce⊃FnMut⊃Fnとなり、Fnが最も制限がきつくて集合としては小さい。
蛇足だが、fnはさらに制限がきつくて読み取り参照キャプチャすら許容されないから、Fn⊃(safeなfnの集合)となって、safeなfnは任意のクロージャの位置で代わりに使える。

例えば、LazyLock::new(f: F)のような、1回しか指定クロージャが実行されない高階関数では、最も緩いFnOnceでトレイト境界「F: FnOnce」を指定できる。
逆に何度もクロージャが実行されるIterator::fold(init, f: F )では、初期値initは消費されるが、fがキャプチャした値が消費されては困るためFnOnceではダメで「F: FnMut」となり、fの引数二つは毎回消費できる。
2025/03/12(水) 21:01:47.70ID:BjrFEung
>>428
一番重要な独自の分類方法を最初にまとめて書かないからクソ記事になる
2025/03/12(水) 21:52:39.29ID:m5dRvsnl
>>430
>クロージャの引数は、毎回変わるのだから常に何をしても自由であり

なるほど。言われてみれば納得。
ありがとう
433デフォルトの名無しさん
垢版 |
2025/03/13(木) 02:14:17.95ID:RNV6T1tE
なんでtypescriptのソースをrustに移植できないの?
プログラムなんだから不可能ってことはないでしょ?
2025/03/13(木) 04:38:06.94ID:RfjEKuUj
>>433
出来ることと効果的に出来ることは別というシンプルな話。
2025/03/13(木) 07:14:12.10ID:93baVECr
TypeScriptのコンパイラはその利用の多さからもっと高速さを狙ってC/C++・Rust・ZigなどのGC非依存言語で書く価値がありブラウザ上Wasm実行の観点からもそうすべきだったが
担当者の能力不足のため遅いGC依存言語から速いGC依存言語へ書き換えるだけで終わってしまった
そのため早くもWasmでの実行が遅いという指摘が出ている
2025/03/13(木) 07:27:03.63ID:gAHIvnwi
要するに、GC依存症の人にはrustは過ぎた物って事か。
2025/03/13(木) 07:45:56.77ID:FfpB+bg4
アンダース・ヘルスバーグが能力不足なんて話があるかいな。
Rust や C# が得意なのにあえて Go を選定したんだぞ。
WASM 上で遅いのは WASM のほうの性能不足だ。
Go の優秀さはランタイムサポートの作り込みにあり、それが十全に発揮されない環境ではそりゃ遅い。
2025/03/13(木) 07:53:47.23ID:TRbLLvdR
Rustで書けばwasmの件も問題なかったわけだからGoという中途半端な言語を選んだ選択ミスだな~
2025/03/13(木) 08:52:01.37ID:FfpB+bg4
WASM ってそんなに絶対に考慮が必要なほど重要なプラットフォームか?
コンパイラを WASM 上で動かそうとする判断をするやつがいたらそのほうが選択ミスだろ。

TypeScript からの移植という前提があったから Go が比較的やりやすいと判断された。
関数単位でほとんど一対一のベタ移植を出来てる。
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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