Rust part20

■ このスレッドは過去ログ倉庫に格納されています
2023/03/03(金) 00:45:28.73ID:vTVY069B
公式
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 part19
https://mevius.5ch.net/test/read.cgi/tech/1673926892/

ワッチョイスレ
プログラミング言語 Rust 4【ワッチョイ】
https://mevius.5ch.net/test/read.cgi/tech/1514107621/
2023/06/26(月) 18:26:13.57ID:H3+gGIMJ
すいません、くだらない質問かもしれませんけど割り込ませて下さい
Haskellとかだと二項演算子(+)はNum classに属する型なら適用できます
自分が作った型でもその型において(+)をどう実装するか定義すれば(+)が利用できるようになります
例えば5元体の計算を行うF5 型を定義してそこで足し算とかをするには

data F5 = F5 Int deriving (Eq,Show) -- 型F5を作成
instance Num F5 where -- F5がNum classに属する宣言
 (F5 x ) + ( F5 y) = F5 $ mod (x+y) 5
...略...

のようなものを作れば例えば

print $ ( F5 3 )^4

でF5 1を得る事ができます
同じような事はRustでできますか?
自分でこのような5元体の計算を行うための型を自作しそれの計算を二項演算子(+),(*)を用いた表記を可能にする方法とかありますか?
2023/06/26(月) 18:32:46.35ID:DZPgqn/v
>>730
std::ops::Add を実装すれば + が使えるし
std::ops::Mul を実装すれば * が使えるよ。
https://doc.rust-lang.org/std/ops/trait.Add.html
https://doc.rust-lang.org/std/ops/trait.Mul.html
2023/06/26(月) 19:00:39.37ID:PhkZx7XR
>>731
ありがとうございます
やってみます
2023/07/04(火) 01:09:18.95ID:2CEMaM2m
神クラス的なArcMutexのstructをごっそり差し替えし始めたらrust analyzerが糞遅くなって書くのが辛い
コード戻したくなる
助けて
2023/07/08(土) 03:39:28.67ID:kPVzZee0
キーボードの何かのキーが入力されてるか調べるけど
何もない場合は止まらずにそのまま次の処理を続けるはどうすればいいの?
2023/07/08(土) 04:25:29.10ID:hz58RfSC
>>734
C言語の時と同じ
ノンブロッキング指定するだけでなく
cooked modeではなくraw modeをICANONに指定
これでバッファリングされることなくブロックされることなく読み出せる
libc叩かなくてもtermioなど好みのクレートを使う
2023/07/08(土) 07:46:14.85ID:kPVzZee0
なるほど
2023/07/08(土) 08:39:38.42ID:kPVzZee0
窓だからGetAsyncKeyState呼び出すのが楽っぽい
738デフォルトの名無しさん
垢版 |
2023/07/13(木) 13:31:51.91ID:B+tQlcfl
Rust言語で開発したWindowsカーネル、Canaryチャネルで展開開始
https://news.yahoo.co.jp/articles/de16ce55a291d59f7364096690fd601c5ee2ece2
739デフォルトの名無しさん
垢版 |
2023/07/14(金) 11:16:58.08ID:tzjfWmow
値をコピーせずに参照を切り替えてFibonacci数列を計算したい

https://ideone.com/lnMyvH

はいけるんだけど

https://ideone.com/VerTGV



error[E0658]: destructuring assignments are unstable

と怒られます
どなたか対処法わかりますか?
2023/07/14(金) 11:27:16.72ID:Jafjy1es
>>739
これでどう?
https://doc.rust-lang.org/std/mem/fn.swap.html
741デフォルトの名無しさん
垢版 |
2023/07/14(金) 12:09:03.76ID:8J2hXx2d
>>740
おお、素晴らしい
あざっす
742デフォルトの名無しさん
垢版 |
2023/07/14(金) 12:17:12.18ID:8J2hXx2d
ちなみにコレxとyの参照してる値を保持してる内容を入れ替えてませんよね?
xとyの参照してるアドレスの入れ替えをしたいんですけど
それどうやって確かめたらいいんでしょう?
743デフォルトの名無しさん
垢版 |
2023/07/14(金) 12:25:35.09ID:8J2hXx2d
そもそもうまく行ってると思ってたほうもうまくいってなかったorz

https://ideone.com/rny4y8

xとyの参照が切り替わってるんではなくて値そのものこくかんしてやがる
xとyの値に触らずxとyの参照先アドレスだけ切り替えるのってできないんでしょうか?
744デフォルトの名無しさん
垢版 |
2023/07/14(金) 12:36:55.78ID:8J2hXx2d
ちょっと長くなるけどやりたい事書きます
例えばFという処理があってそれを初期値a0に何度も適用したいとします
Fの値を計算する関数を入力バッファと出力バッファのアドレスをとって入力バッファ側のデータを読んで出力バッファに書き出す関数を作ったとします
それを何度も繰り返す場合、出てきた出力バッファの内容をもう一度入力バッファにコピーする作業はあまりにも無駄なので出てきた出力バッファを今度はそのまま出力バッファとして使用したいんです
でもx,yは参照型でy=xとしたら何故かxの内容をyの内容に置き換えてしまってるみたいですけどコレ何故なんでしょう?
なんとかならないんですか?
745デフォルトの名無しさん
垢版 |
2023/07/14(金) 12:57:26.91ID:KGL+WmuV
自己レス

わかりました
こうですね

https://ideone.com/sl7Q9v

ここまではうまく行った
746デフォルトの名無しさん
垢版 |
2023/07/14(金) 13:20:43.04ID:bUq24laG
そして教えていただいたsys::mem::swapで確認
うまく行ってる感じです
素晴らしい
あざっす

https://ideone.com/1pWNZ7
2023/07/14(金) 13:21:19.50ID:i4/iEcAZ
そもそもE0658がideoneのrustcのバージョンが古すぎるせいだから>>1のPlayground使ってろ
2023/07/14(金) 19:05:41.95ID:qocfo89A
亀だが
>>694
>基礎から学ぶ組み込みRust
見てきた。あの内容じゃWebの記事読んでおけば十分な感じだった
肝心の低レイヤー(CPUやペリフェラルとのインターフェイス)の解説がペラい
特に現状ではメーカーのサポートが得られない以上HALやBSPに相当する部分を
自前で用意せざるを得ないケースは少なくないと思うけど
その辺が十分に解説されているようには見えなかった
2023/07/14(金) 21:27:06.52ID:+dZRH6iE
そりゃマイナーなチップのHALを自分で作るなんて
マニアックすぎる内容で商業出版は無理だろ
そこまでやるならもう既存の実装見に行ったほうが早いよ
2023/07/17(月) 14:57:59.69ID:ckC6D+AP
期待してたけどめちゃくちゃ頼りないスタイルガイドが出てきたな
「こういう場合はこうフォーマットしましょう」だけじゃなくもう少し踏み込んで欲しかった
https://doc.rust-lang.org/nightly/style-guide/statements.html
2023/07/17(月) 15:40:03.84ID:qDsaxMYb
スタイルガイドの目的はrustfmtの挙動を文書化して開発を進めやすくするってことだから
まさに「こういう場合はこうフォーマットしましょう」のための文書だよ
752デフォルトの名無しさん
垢版 |
2023/07/17(月) 17:17:17.76ID:WT/Een/k
もう少し踏み込んで欲しかった、と言ってる人にそれを言ってもどうもならないわな
別にスタイルガイドの定義の話あなたが勝手に始めただけですよね
論破ですよね
2023/07/17(月) 17:39:41.44ID:Lx49eL3d
なにいってだこいつ
2023/07/18(火) 03:22:09.12ID:wb1VWGHJ
>>744
ポインタとポインタのポインタの違いだな

>>746
そう
ポインタのポインタをswapに渡せばポインタが書き換わる
2023/07/18(火) 03:37:10.43ID:wb1VWGHJ
>>750
従来の言語のスタイルローカルルールの乱立やルール解釈の違いなどの反省から
Rustの標準ではrustfmtを使うことに尽きるわけだがそれ以上にどんな記述を求めているのだろうか
756デフォルトの名無しさん
垢版 |
2023/07/18(火) 09:14:53.67ID:nuoH1aU3
一般的なスタイルガイドを知ってる人と知らない人の違いだね
常識だと思ってた
757デフォルトの名無しさん
垢版 |
2023/07/18(火) 13:02:43.58ID:W9LkQalw
公式のスタイルガイドはrustfmtに実装するフォーマッティング以外はスコープ外
フォーマッティングガイドラインと改名したほうがいいわな
2023/07/19(水) 11:14:31.27ID:HXkvqxP4
関数呼び出しの質問です
私の認識では
「rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される、ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない」
であってますか?
それでお聞きしたいのはrust compilerって呼び出した関数側が実際引数を変更するかしないか判定して“immutatibleな変数を変更しようとした、なめとんかボケ”って怒ってくることがあります
コレ逆に言えば例えプログラマが変更しない変数をmutableで呼び出しを指定してもcompilerはどうせ変更されないんだからコピーもしないでいいよねと気を利かせてコピーしないとかしてくれると考えて大丈夫ですか?、
2023/07/19(水) 11:21:25.92ID:yw4UHEnD
>>758
言ってることが意味不明なので回答できない。
何か根本的に勘違いしていると思う。
コードで説明してみて。
2023/07/19(水) 11:41:04.52ID:HXkvqxP4
すいません
具体的なコーどはちょっと用意します
別件なんですけど

let mut i : u64;
let p : u64 = 2u64.pow(32)-2u64.pow(10)+1;
for i in 2..100000 {
if i.pow(524288)%p != 1 && i.pow(1048576)%p == 1 {
println!("{}",i);
}
}
と書いたところ
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
--> compiler.rs:136:8
と怒られます
u64って指定するだけではダメなんでしょうか?
どう書いたら通してもらえますか?
よろしくお願いします
2023/07/19(水) 11:47:10.22ID:x9es5cRL
unsafe { 引数のポインタ拾って描き替えたら }
呼び出し側も描き換わってたでござる
2023/07/19(水) 11:49:41.95ID:x9es5cRL
>>760
for i in 2..100000u64 {
2023/07/19(水) 11:51:21.32ID:x9es5cRL
>>762
あと mut i: u64 の i は for では使われてないし警告出てない?
2023/07/19(水) 12:00:23.67ID:HXkvqxP4
ダメでした

error[E0308]: mismatched types
--> compiler.rs:136:12
|
136 | if i.pow(524288u64)%p != 1 && i.pow(1048576u64)%p == 1 {
| --- ^^^^^^^^^ expected `u32`, found `u64`
| |
| arguments to this function are incorrect
|
note: associated function defined here
= note: this error originates in the macro `uint_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
help: change the type of the numeric literal from `u64` to `u32`
|
136 | if i.pow(524288u32)%p != 1 && i.pow(1048576u64)%p == 1 {
| ~~~

となります
powってu64はダメなんでしょうか?
2023/07/19(水) 12:07:25.53ID:HXkvqxP4
ideoneでもダメです
https://ideone.com/FaBKXh
766デフォルトの名無しさん
垢版 |
2023/07/19(水) 12:11:42.11ID:a/a2TjKK
エラーメッセージから「ダメ」かどうかの1ビットしか読み取らない人にプログラミングは難しい。
2023/07/19(水) 12:12:42.07ID:HXkvqxP4
あ、そもそもコレダメですね
仮にu64受け付けてくれてもダメやん
powは自作します
しかしu64版のpowってないんでしょうか?
2023/07/19(水) 12:14:10.94ID:x9es5cRL
overflowは知らん自己責任でやれ
https://ideone.com/JR2FhX
2023/07/19(水) 12:17:18.80ID:x9es5cRL
>>767
https://crates.io/crates/rust-gmp
2023/07/19(水) 12:25:20.07ID:YST94QZy
いろいろキッツいなぁー

loop-variableはfor-loopのブロックスコープ
u64::powはfn pow(self, exp: u32) -> u64
(u32以上の値をとってもオーバーフローするから)

>「rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される、ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない」
>であってますか?
もちろん間違ってます
771デフォルトの名無しさん
垢版 |
2023/07/19(水) 12:29:53.08ID:hsqLjzEB
余りをとっているから繰り返し自乗法を適当に実装すればオーバーフローは回避できる
2023/07/19(水) 12:30:35.45ID:HXkvqxP4
>>770
間違ってるんですか?
どこが違いますか?
2023/07/19(水) 12:41:14.04ID:HXkvqxP4
>>771
そうなんですよ
毎回あまり取らないとダメですよね
pの値も間違ってたし
やりたかったのはバッファサイズが1048576の有限体のフーリエ変換のための素数と位数1048576の元zetaを見つける作業でpはすぐ見つけてたんですけどzetaで手こずりました
まだrust慣れてないもので
これで行けました
https://ideone.com/haw9t8
見つけたzetaの候補3つ
4293918721
1557
7183
8874
2023/07/19(水) 15:49:39.29ID:HXkvqxP4
やはりダメです
型の指定の書き方がわかりません
次のコードです
https://ideone.com/QLw12c
有限体上のFourier変換を書きたいんですけどmutの書き方がらみで怒られます
どうすれば通せますか?
2023/07/19(水) 16:22:53.10ID:HXkvqxP4
とりあえずmutを全部につけまくったら通りました
https://ideone.com/EF9EEJ
776デフォルトの名無しさん
垢版 |
2023/07/19(水) 17:34:17.58ID:g8hXxOtp
>>774
>どうすれば通せますか?
The Bookを読んで基本を身につければ通せます。
https://doc.rust-lang.org/book/
まずはplygroundとエラーメッセージの読み方から学ぶことをお勧めいたします。
2023/07/19(水) 17:52:11.79ID:HXkvqxP4
ありがとうございます
コンパイルは無事通ったんですけどstack overflowで実行できませんでしたw
どうせならどでかいのでやってみようと欲張ったらダメでしたw
まぁ縮める分には見つけたpやzetaはそのまま使えるのでまた時間ある日に続きやります
やっぱり新しい言語挑戦するのは時間かかりますね
ついでにひとつお聞きしたいんですけど、今回は「Rustの売りのなるべくstuckでやる」でやってみたんですけど流石にこのサイズはstackにとれないようです
コレ同じ事ヒープでやってもRustコンパイラはフラグメンテーションが怒らないように良きにはからってくれますよね?
コードは>>775です、まだ作りかけですけど
Fourier変換でO(n log n)で掛け算するプログラムの実装の演習の自習中です
2023/07/19(水) 23:54:55.34ID:6nPpRSza
>>758
>> rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される

Rustは常にcall by valueでvalueをコピーする
大きなものをコピーされたくないならば
渡すvalueとしてその参照を指定する
すると参照すなわちポインタ値のみがコピーされて渡される

>> ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない

immutatibleな呼び出しなんて概念はない
immutableな参照を渡すかmutableな参照を渡すかの選択肢はある
そのポインタ値は常にコピーされる

ポインタ値のコピーはどんな速い言語を作っても避けられずそれが最速
ただし例えば数値単体を渡すなら参照(ポインタ値)を渡すよりも速い

>>777
数MBのデータはスタック領域に入らないのでヒープ領域に開始時に確保すればよい
2023/07/20(木) 15:25:39.14ID:6BSTmMYa
>>778
>Rustは常にcall by valueでvalueをコピーする

何でもかんでも #[derive(Copy, Clone)] 描く習慣は良くないな
780デフォルトの名無しさん
垢版 |
2023/07/20(木) 16:14:28.16ID:zz9s86Uo
古典的なcall by valueの定義におけるコピーと
そのCopyとはまた違う話

ついでに言うとRustにおけるcall by valueの定義と
古典的call by valueの定義は違うので要注意
現代では古典的定義でcall by valueかどうかを考えるのはあまり意味がない
2023/07/20(木) 19:56:50.64ID:neDY19sM
>>779
そのコピーはビットコピーの話でCopy実装型の話とは別
Copy非実装型でもムーブするとビットコピーされる
そもそもCPUやメモリにムーブなんてものは存在しなくてMOV (MOVE)命令ですらビットコピーが行われる

ただしビットコピーは最適化で消えうる
例えば別の変数にムーブしても最適化でビットコピーは消えうる
サイズの大きな値を関数でムーブ返ししてもRTO (Return Value Optimization)により呼び出し元スタックフレームに直接生成できるならビットコピーは消えうる
サイズの小さい値を関数でムーブ返しするとレジスタ返しとなる等
782デフォルトの名無しさん
垢版 |
2023/07/20(木) 22:07:49.98ID:YJW86g9/
call by valueのコピーはビットコピーなんて定義はない
ビットコピーかどうかはimplementation detail
2023/07/20(木) 22:17:52.36ID:mzA35L2k
レジスタかメモリへのビットコピー以外に渡す手段はない
現行のコンピューターでは
2023/07/22(土) 01:08:25.26ID:9fslOp72
メモリ管理について質問です
Rustは「GCをしない言語」を謳っています
一応「GCを心配する必要はない、フラグメンテーションなも起きない、メモリ不足になったらそれはフラグメンテーションではなくて元々のメモリ不足」と言い切れればいいんですけど、実際にはそうではなく、下手なデータ管理をすればフラメンテーションは発生するようです
まぁそりゃそうなんですけど
https://hackernoon.com/ja/Rust%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E6%96%AD%E7%89%87%E5%8C%96%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%81%A6%E5%9B%9E%E9%81%BF%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
ということはプログラマ極力フラグメンテーションが発生しないように注意したいところですが、しかしRustのアロケータはどういう状況でフラグメンテーションを発生させるか、どうやれば防げるかの資料が見つかりません、なので先のリンクの人は自分で調べてたみたいです
これ誰かご存知の方いますか?
具体的には同じ型のSizedのデータA,を作成して先にAを消し、その後同じ型のCを作った場合、Rustシステムはその時点で開いてる穴のAの抜け穴を利用してそこにCを割り当ててくれるんでしょうか、
それともBが消えるまではAのあった場所も“欠番扱い”になるんでしょうか?
2023/07/22(土) 02:40:42.91ID:htX2UcZa
>>784
アロケーションやフラグメンテーションはRustの言語システムの範囲外
例えばOSがない環境も含めてアロケータを自作もできるようになっている
普通にOSなどある環境を使うとRustはそこでの標準のアロケータをそのままグローバルアロケータとして用いる
つまり環境毎に異なるものが使われていてRustとは全く関係がない問題であることがわかる

もちろんRustでは自分でアロケータを変えることもできる
グローバルアロケータを丸ごと変える方法とBoxやVecなどで個別にアロケータを指定する方法がある
使用環境の標準のアロケータで何か問題が起きていると感じたらその例のように別のものと交換して比較してベストなアロケータを選べばよい

もう一つ全く別のアプローチとしてそれらアロケータに頼るのではなくプログラムのレベルでまとまったメモリの割り当て管理する方法もある
この方法は全て自分の制御下におけるため様々な特性のあるクレートがありもちろん自作もできる
2023/07/22(土) 02:50:52.30ID:htX2UcZa
>>784
後半の質問はもちろん再割り当てしてくれる
どの環境の標準アロケータでもそのような普通のことは当然している
だからアロケータの変更などは何か問題が起きてから考えればいい
質問の挙動ならばアドレスを表示させればわかる

fn main() {
// aを割り当て
let a = foo(123);
println!("a: {:p}", &*a);
// bを割り当て
let b = foo(456);
println!("b: {:p}", &*b);
// aを解放
std::mem::drop(a);
// cを割り当て
let c = foo(789);
println!("c: {:p}", &*c);
// aとcは同じアドレスになっている
}

fn foo(init: i32) -> Box<[i32; 1000]> {
std::boxed::Box::new([init; 1000])
}
2023/07/22(土) 08:56:00.85ID:40PxJ+ku
やはりそうですね
Rustはヒープエリアのメモリ管理は言語システムでは提供しない、その性能については規定しない立場なんですね
なので先の質問のような場合「Rustでは必ずうまいことやってくれる」とは言えず「コンパイラ××、実行環境××で実測したらうまく行った」程度しか言えず、同じソースを別の環境に持ってやったらダメだったもありうるんですね
結局ヒープを使わざるを得ない場合には「自分でメモリ割り当てをうまいことやる」しかないんですね
今やってる例だとスタックには入らないって怒られるし、ヒープ使うなら、うまくいくかはやってみるまでわからないというのはちょっと面白くないなぁ
2023/07/22(土) 09:24:29.44ID:htX2UcZa
>>787
OS環境などが提供するアロケータ(=Rustのデフォルトのアロケータ)をそのまま使う時だけ環境依存になる
これはRustに限らずそれをそのまま使う全てのプログラミング言語で起こるためRustの問題ではない
しかもRustは次のように解決策がある言語だ

アロケータ含めて同じソースを持っていってそれを使うならば動作も同じになるので大丈夫
例えば先ほどのケースのようにjemallocをアロケータとして指定して使えば環境依存ではなくなる
よほど特殊なケースでの特殊な効率化を目指さない限り自分でアロケータを書く必要はない
2023/07/22(土) 09:54:09.20ID:JFG0S3Tm
まぁそうですね
Rustにしたら今までのプログラミング言語で常に問題視されてたアロケーション問題が魔法のように解決するなどという事があるはずはないですね
2023/07/22(土) 09:59:59.87ID:htX2UcZa
何を問題にしているのか明確にせよ
Rustはアロケータすら自由に入れ替えられる
つまり理論上可能なことはRustならば解決できる
791デフォルトの名無しさん
垢版 |
2023/07/22(土) 10:40:08.11ID:S6pKsqQS
複オジーww
2023/07/22(土) 10:45:39.31ID:xU//sEEH
問題は普通のプログラミング言語の“メモリ割り当て問題”です
別にRust特有の問題ではなく、どんなプログラミング言語でも発生する問題ですよ
Rustではどういう戦略で当たってるのかなと
もちろんこの戦略に関して“どんな場合でもうまくいくまほうのような解決策”などありません、そして多くの場合この処理は大変重たい処理でとても重大な問題を引き起こします
画像処理、動画処理、AIの機械学習の処理などで大きなデータの割り当て、更新、消去は処理中かなり頻繁に起こり、データサイズによってはフラグメンテーションが大きな問題になる事などしょっちゅうです
結局プログラマはほとんどの場合自前でアロケーション問題を解決させられるわけでそこにもはや“言語のデフォルトに任せておけばいける”幻想は抱いてません
しかしRustはどうしてるんだろうと、もしRustでやれといわれた場合があったと妄想して自分にそれができるようにしときたいなと思って自習中なんです、まぁ絶対なさそうですが
今まで色々資料読んだ範囲内だと感覚的には「Rustはメモリ管理に関しては言語内部的には頑張らない、外部環境で処理するか、可読性を犠牲にガチャガチャしろ」というスタンスで提供されてる感じはしてます
2023/07/22(土) 11:31:54.16ID:l0FUWY0y
>>792
Rustは可読性を一切犠牲にすることなく、ソースコードそのままで、グローバルアロケータ指定だけを追加すればアロケータを変更できる
この件に関してRustは最も融通が効く優れた言語の一つ
2023/07/22(土) 11:35:08.26ID:nQhdUCcc
この人はそういう人なので適当に切り上げることをおすすめします
2023/07/22(土) 11:38:03.03ID:xU//sEEH
まぁ無理です
できないことをできると言い張るのはもはや学問ではなく信仰です
2023/07/22(土) 11:49:43.86ID:YLqzZrt5
A造る
B造る
A消す
C造る
AのサイズよりCのサイズが小さいとき
A-Cのサイズ分のフラグメントが発生
2023/07/22(土) 12:06:07.26ID:24bvSiNd
>>792
>> 今まで色々資料読んだ範囲内だと感覚的には「Rustはメモリ管理に関しては言語内部的には頑張らない、外部環境で処理するか、可読性を犠牲にガチャガチャしろ」というスタンスで提供されてる感じはしてます

メモリ管理の階層の違いを理解できていなさそうだが
メモリアロケータの話ならばRustはC++と同様に交換自由でライブラリ選択可能
可読性を犠牲にガチャガチャする必要はなくRustでは#[global_allocator]で指定するだけで交換可能
2023/07/22(土) 13:41:17.13ID:7Mz5wCRP
理解できてなかったらしい
もういいや
2023/07/22(土) 13:57:51.76ID:u4m8T///
>>792はC言語でたとえるとmallocを使ったメモリ管理とmallocの中のメモリ管理の違いをわかっていない初心者かな
2023/07/22(土) 13:58:55.74ID:NWfMWzFP
そうです
初心者でした
お騒がせして申し訳ありませんでした
801デフォルトの名無しさん
垢版 |
2023/07/22(土) 14:25:05.31ID:AxAuiZIS
>>796
AのサイズよりCのサイズが大きいときは
フラグメントは発生しないのかな?
2023/07/22(土) 14:42:32.24ID:QLIAp4G5
>>801
そんなに単純じゃないよ。
確保しようとする大きさによって違う領域から割り当てるような実装も普通。
順序良く割り当てるわけではなく、
そのときの状況によって効率的になるように采配する。

仮に断片化を意図的に起こしてでも総合的に断片化の確率を減らすような
戦略を持っているのかもしれないし、
よほど深刻な場合を除いて使う側はアロケータの中なんぞ忘れておくのが吉。
2023/07/22(土) 14:54:17.36ID:NWfMWzFP
もちろん発生しますよ
どんな場合でも最高次数にうまくいく魔法のような戦略なんてありません
なのでケースバイケースで場合に応じて戦略を使い分けなければならない
しかしOSの実行環境なんかのアロケーターはプログラムの内部情報を何一つ持ってないから「開きメモリのリストを持っておいて最初に見つかったスキマにアサインする、足りなくなったらGC」以外に戦略の採りようがない、だから従来のプログラミング言語は自分でGCするわけです、少なくともコンパイラはコンパイルする時点でどれくらいの頻度でどれくらいのサイズのアロケーション要求が発生するかある程度情報が得られるからそれを利用してよりよい割り当て戦略をとれるチャンスがあるからです、なんならその情報をコンパイラに教えるnotificationをつけられるように設計する事もできる
しかしそれとて限界がある、だからRustはもうそれすらやらない、アロケーションは自分でやれ、そのためのツールはある程度は言語内部で用意する、ダメなら言語外部のツール使え、という「無理してやってもどうせ“最適”には程遠いからやらない」んでしょう
逆に言えばRustでプログラム組むとき、特にでかいデータの作成、廃棄を繰り返すような場合はプログラマはかなり練度が必要になるんでしょう
立ち位置としてそれくらいの事がこなせるユーザーをプログラマとして想定してるという事です
学習コストが高いんじゃなくてそもそもプログラマに要求されてる水準が高めなんですね
2023/07/22(土) 16:19:13.40ID:2BLjTz4O
>>803
間違い多いな
まず一般的にGCはフラグメンテーションを解決しない
特にマークアンドスイープ方式のGCや参照カウント方式のGCはフラグメンテーションは放置で関与しない

Rustについての記述は間違いだらけでなんとも言いようがない
言語外部のツール使えとはトンデモすぎて何を言ってるのかもわからない

フラグメンテーションを起こし得るメモリアロケーターについてRustはC/C++と同じ立場で同じものを使う
C/C++/Rust共通の話として同じようにjemallocなど別のメモリアロケーターを使うことができる
Rustだけ特別な方法をとったり特別な性質をもったりはしておらずフラグメンテーションについてもC/C++と同じ
2023/07/22(土) 16:41:16.06ID:NWfMWzFP
素人なものですいません
スレ汚しすいませんでした
806デフォルトの名無しさん
垢版 |
2023/07/22(土) 17:02:30.53ID:NRmzieuj
>まず一般的にGCはフラグメンテーションを解決しない
マーク&スウィープ方式は一般的にコンパクションもやってるぞ
2023/07/22(土) 17:07:41.36ID:2BLjTz4O
>>806
コンパクションをするかしないかは独立した問題
マークアンドスイープ自体はコンパクションを伴わない
2023/07/22(土) 17:59:22.96ID:QLIAp4G5
>>807
再配置できないならそもそも論外なんだから
無関係ではないだろ。
2023/07/22(土) 18:05:22.75ID:YLqzZrt5
そういえば君らのメモリ管理の会話でLinkedListの使い道思い出したわ
Rustやその他の言語側じゃなくてOS側のメモリ管理にLinkedList使われてるわ
2023/07/22(土) 18:42:28.71ID:2BLjTz4O
>>808
再配置するのはコピーGCで使用中データ全移動と全ポインタ書き換えとなる
マークアンドスイープGCはその名の通り使用中を辿りマーク付けしてマークされなかったものを再び未使用領域とする
811デフォルトの名無しさん
垢版 |
2023/07/22(土) 19:01:55.55ID:TsQs+vXV
>>807
論点は”一般的”にやってるかどうかだろ
君は一般的にやってないと言ってるわけで
JavaもC#もJavaScriptもみんなGCでcompactionやってる
2023/07/22(土) 19:18:33.46ID:2BLjTz4O
>>811
compactionをする前にマークアンドスイープGC自体は既に終わっていて独立した別の行為
実際にそれら言語では世代別GCが行われていていて新入り若手のオブジェクトはコピーGCを行なうが古いオブジェクトはマークアンドスイープのみで再配置しない方法が一般的
2023/07/22(土) 19:31:27.25ID:nB6v7J6K
隔離スレ行けアスペジジー
2023/07/22(土) 20:04:44.58ID:2BLjTz4O
再配置はデータコピーとそこへのポインタ全て書き換えでコストが大きすぎるから可能な限り避けるのが正しい
世代別GCで若手オブジェクトだけに限ってコピーGCの対象にするのも若手の大半は一時的利用でコピーしなくて済むため

Rustではそんなコストをかけないだけでなくヒープ確保解放のコストすら減らすことと一石二鳥で解決する方法も取られている
例えばbumpalo crateはまとまった領域を持って追記していくだけで個別の解放コストゼロ(=何もしない)と個別の確保コストも最小(=追記のみor足りないとまとまったお代わり)のアリーナアロケータ
つまり未使用領域の再利用をしないことで管理不要となり最高速になるとともにまとめて一気に最高速で返す
具体的にはサーバーまたはバッチ処理で各対象固有データのみそこから確保してその対象を終える時に破棄
これはフラグメンテーションを防ぐのに非常に効果的な方法
815デフォルトの名無しさん
垢版 |
2023/07/22(土) 21:33:49.24ID:kHWj4RWJ
まーた複オジが知ったかぶりして無知晒してるw
初心者かなww
816デフォルトの名無しさん
垢版 |
2023/07/22(土) 22:04:25.70ID:kdu4dn9d
Rust使うくらいならJavaかC#で良いのでは?
2023/07/22(土) 22:08:51.83ID:wR/xGD2g
RustとC#だとどっちがいいの?
2023/07/23(日) 02:44:41.28ID:lmJrnSr9
>>814
GCのないRustが速いわけだ
2023/07/23(日) 11:09:10.60ID:kMNWXVHy
>>814
C/C++でも同じアルゴリズムのアロケータあるで
2023/07/23(日) 11:10:16.97ID:dOw1chPf
>>816
🤮
2023/07/25(火) 06:32:45.09ID:7X7HwnNv
>>819
言語に関係なくそこへ行き着くんだよな
もちろん通常はフラグメンテーションなんか気にせずに普通にコードを書けばよく
稼働時間の長いプロセスでフラグメンテーションが実際に起きた時の解決策の一つ
2023/07/27(木) 13:16:19.02ID:/bGsBsBb
play-rustのコードのコピペのやり方教えて下さい
具体的にはお題スレの

https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=f627f3a5de4a0c467f015a8b1527c141

のコードコピペする方法がわかりません
よろしくお願いします
2023/07/27(木) 14:04:04.46ID:90/I2Z5n
rustは型推論をしてくれると聞いたのですけど、結果どういう型になったか調べる方法はありますか?
Haskellのghciの:tに当たるやつです
例えはghci内で
prelude> let f n = sum [ x^n | x<- [1..5] ]
として
prelude> :t f
とすれば
( Num a, Integral b ) => b -> a
のように返してくれます
rustでコンパイラの型推論の結果どういう型に決定したのか調べる方法はありますか?
2023/07/27(木) 14:28:57.60ID:p+3LvAw4
>>823
LSP 対応のエディタ (VSCode など) を使ってるならそのへんにカーソルを合わせるだけで型は見れるよ。
2023/07/27(木) 21:59:53.82ID:x4QyUuiY
>>823
安直な方法としては関数の戻り型なら -> i32と嘘の型宣言を指定すれば型不一致で正しい具体型をコンパイルエラーに表示してくれる
プログラムで表示したいならこれ
fn get_type<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
2023/07/27(木) 23:11:30.70ID:sTDTKxns
>>824
>>825
あざっす
2023/07/27(木) 23:12:33.60ID:paov2RlH
rustの型推論って曖昧なことを許容したっけ?
すべて一意にならないとならないと思ってたけど
2023/07/28(金) 19:39:32.86ID:4cjf/6GX
>>827
正しい
ジェネリックであってもパラメタは各々で必ず一意に静的に確定せねばならず
impl Traitで型宣言しても各々で一意に具体的な型に静的に確定する
特にそれが関数の引数ならば生成コードは単相化される

ただしdyn Traitはそれらが静的ではなく実行時のオブジェクト生成毎に個別に一意の具体的な型に確定する点で異なる
コンパイル時の静的な生成コードは複数の型で共有となるためvtableを持って対処している
2023/07/29(土) 16:54:29.41ID:Nh9kevR9
なるほど
Rustは最終的にコンパイルが終わって型が完全に推論が終わって単相型が決定した状態でしかわからないのかな
当然get_typeで得られるstrは推論終わって単相型が割り当てられた後の型しかわからないんやな
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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