公式
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/
Rust part14
■ このスレッドは過去ログ倉庫に格納されています
2022/02/12(土) 01:24:16.59ID:XYE+Rws6
2022/02/15(火) 16:20:56.03ID:yLJ5RfL8
look aheadのパターンにしたかったのかな
Peekableならnext_ifがいい感じにはまりそう
...
let mut is_debug = false;
let mut is_quiet = false;
while let Some(option) = args.next_if(|s| s.starts_with("-")) {
match option.as_str() {
"-d" => is_debug = true,
"-q" => is_quiet = true,
"--" => break,
_ => usage(),
}
}
if args.len() != 1 {
usage();
}
...
Peekableならnext_ifがいい感じにはまりそう
...
let mut is_debug = false;
let mut is_quiet = false;
while let Some(option) = args.next_if(|s| s.starts_with("-")) {
match option.as_str() {
"-d" => is_debug = true,
"-q" => is_quiet = true,
"--" => break,
_ => usage(),
}
}
if args.len() != 1 {
usage();
}
...
2022/02/15(火) 22:18:31.12ID:57mqcwZM
2022/02/15(火) 22:42:34.06ID:57mqcwZM
2022/02/15(火) 23:44:22.03ID:je481k6i
どちらも文字列の先頭数byte参照するだけだから大差ないよ
as_* じゃなくて to_* を使うとかだと差が出るかもね
as_* じゃなくて to_* を使うとかだと差が出るかもね
2022/02/16(水) 01:25:58.91ID:3jEsfDTa
短くてもいつもの汚コード氏だと分かるコードなのがすごい
2022/02/16(水) 18:46:05.60ID:4BNkCNLv
>>20
他にも色々方法がある
例えば落とし穴だが一番表記が短いスライス &(&s)[..1]
ただし空行をs.len()で回避した場合でも
if "#" == &(&s)[..1] { これは先頭が非ASCIIだとpanicなので注意
utf8境界を見極めて最初の1文字を取り出すには面倒で
if "#" == &(&s)[..s.char_indices().nth(1).unwrap().0] { となり本末転倒
なので最初の1文字を取り出すには普通はイテレータchars()を使って
if Some('#') == s.chars().next() { となるが
今回は正しく先頭1文字ではなく先頭1バイトを取り出せれば判断できるので
if Some(b'#') == s.bytes().next() { の方が速い
しかしイテレータを使うまでもないから
if Some(&b'#') == s.as_bytes().get(0) { と配列アクセスでも十分だろう
先頭は需要が大きいためなのか
if Some(&b'#') == s.as_bytes().first() { と専用メソッドが用意されてるようだ
ただしここでもサボって
if b'#' == s.as_bytes()[0] { とすると空行でpanicするので注意
以上ここまでは先頭取り出し系だがシンプルに
if s.starts_with("#") { が一番わかりやすい
ただしこれは実装でinline指定がないから不利で遅いかもしれない
inlineで&[u8]に読み替えるだけの as_bytes() は確実に速い
あとは get(0) と first() がどちらもinlineでコードが
前者が if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
後者が if let [first, ..] = self { Some(first) } else { None }
たぶん展開して最適化した最終コードは同じになるのではないか
そしてSomeやNoneは最適化で if Some(&b'#') == 部分と反応しておそらく消えると予想しているが
if let [b'#', ..] = s.as_bytes() { と最初からOption使わなければその点も確実という結論か
あとはみんなでツッコミしてくれ
他にも色々方法がある
例えば落とし穴だが一番表記が短いスライス &(&s)[..1]
ただし空行をs.len()で回避した場合でも
if "#" == &(&s)[..1] { これは先頭が非ASCIIだとpanicなので注意
utf8境界を見極めて最初の1文字を取り出すには面倒で
if "#" == &(&s)[..s.char_indices().nth(1).unwrap().0] { となり本末転倒
なので最初の1文字を取り出すには普通はイテレータchars()を使って
if Some('#') == s.chars().next() { となるが
今回は正しく先頭1文字ではなく先頭1バイトを取り出せれば判断できるので
if Some(b'#') == s.bytes().next() { の方が速い
しかしイテレータを使うまでもないから
if Some(&b'#') == s.as_bytes().get(0) { と配列アクセスでも十分だろう
先頭は需要が大きいためなのか
if Some(&b'#') == s.as_bytes().first() { と専用メソッドが用意されてるようだ
ただしここでもサボって
if b'#' == s.as_bytes()[0] { とすると空行でpanicするので注意
以上ここまでは先頭取り出し系だがシンプルに
if s.starts_with("#") { が一番わかりやすい
ただしこれは実装でinline指定がないから不利で遅いかもしれない
inlineで&[u8]に読み替えるだけの as_bytes() は確実に速い
あとは get(0) と first() がどちらもinlineでコードが
前者が if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
後者が if let [first, ..] = self { Some(first) } else { None }
たぶん展開して最適化した最終コードは同じになるのではないか
そしてSomeやNoneは最適化で if Some(&b'#') == 部分と反応しておそらく消えると予想しているが
if let [b'#', ..] = s.as_bytes() { と最初からOption使わなければその点も確実という結論か
あとはみんなでツッコミしてくれ
2022/02/17(木) 10:37:24.58ID:nN2LTJ+a
premature optimizationの典型例
このレベルの最適化が本当に必要ならまずは計測しろ
このレベルの最適化が本当に必要ならまずは計測しろ
2022/02/17(木) 10:41:11.69ID:J5He3Z4Q
百理ある
2022/02/17(木) 11:01:53.16ID:W9idHeI8
結論の if let [b'#', ..] = s.as_bytes() { なら可読性も落ちず意味もわかりやすいからいいんじゃね?
それを満たした上で長さが0でないことと先頭バイトの定数比較コードになると誰もが予測可能
それを満たした上で長さが0でないことと先頭バイトの定数比較コードになると誰もが予測可能
2022/02/17(木) 11:06:38.82ID:reqFguXW
うーんRustのデフォルトがムーブになっているのはおもしろいな
かなり思い切った設計をしている
かなり思い切った設計をしている
2022/02/17(木) 11:42:39.48ID:RuZDOzbq
千里ある
2022/02/17(木) 12:41:58.72ID:TvxpbZK8
2022/02/17(木) 23:06:37.97ID:S7RVNfva
あらためてRustは凄いな
enum Optionで意味わかりやすく安全にプログラミングしつつ
生成コードからはSomeやNoneが綺麗に跡形もなく消え去ってC言語で書いたときと同じになるんだな
enum Optionで意味わかりやすく安全にプログラミングしつつ
生成コードからはSomeやNoneが綺麗に跡形もなく消え去ってC言語で書いたときと同じになるんだな
2022/02/17(木) 23:36:39.74ID:JQNiobes
ML系言語の概念とC的な低レイヤの概念を融合した上で
オブジェクトの依存性の概念も付け加えるというのは実に素晴らしい考えだと私も思う。
個人的には Haskell が好きなんだけどランタイムサポートが重すぎると思ってたので Rust は大歓迎だ。
オブジェクトの依存性の概念も付け加えるというのは実に素晴らしい考えだと私も思う。
個人的には Haskell が好きなんだけどランタイムサポートが重すぎると思ってたので Rust は大歓迎だ。
2022/02/17(木) 23:47:52.93ID:W9idHeI8
ヒープを使うか使わないかと
dynを使うか使わないかの2点だけは
コンパイラも最適化できないのでそれだけ気をつけていれば大丈夫
dynを使うか使わないかの2点だけは
コンパイラも最適化できないのでそれだけ気をつけていれば大丈夫
2022/02/18(金) 08:09:00.13ID:zucTXNEL
>>32
boxを使わない時は常にスタックじゃないの?
boxを使わない時は常にスタックじゃないの?
2022/02/18(金) 08:29:45.01ID:dvRY56uQ
>>33
BoxだけでなくVecやStringなどもヒープを使う
配列[T;N]や配列を使ったArrayVecやArrayStringなどはスタック上のみ使う
dynはBox<dyn ...>の形ならヒープ上だけど&dynの形ならスタック上のみで使うことができる
BoxだけでなくVecやStringなどもヒープを使う
配列[T;N]や配列を使ったArrayVecやArrayStringなどはスタック上のみ使う
dynはBox<dyn ...>の形ならヒープ上だけど&dynの形ならスタック上のみで使うことができる
2022/02/18(金) 09:51:02.85ID:5+RbHFST
>&dynの形ならスタック上のみで使うことができる
ん?
ん?
2022/02/18(金) 10:17:03.62ID:dvRY56uQ
>>35
例えば標準入力stdin()とファイルFile::open()は型がStdinとFileで異なるが
どちらもtrait Readを実装しているから&mut dyn Readに入れることで同じコードでreadできるようになる
このdyn Traitをtrait objectと言って動的ディスパッチとなるが生成コードは一つになる
ちなみにimpl Traitだとコンパイル時に静的に解決されて生成コードは型毎に多数のコードが生成される
trait objectは?Sizedだから直接は扱わずに&dynの形かBox<dyn>の形で使うことになる
&dynの形ならスタック上のみで使うことができるが元の型よりは長く生きられない制限がある
そこで例えば関数の返り値にしたい時などはヒープを使ってBox<dyn>の形にして返す
例えば標準入力stdin()とファイルFile::open()は型がStdinとFileで異なるが
どちらもtrait Readを実装しているから&mut dyn Readに入れることで同じコードでreadできるようになる
このdyn Traitをtrait objectと言って動的ディスパッチとなるが生成コードは一つになる
ちなみにimpl Traitだとコンパイル時に静的に解決されて生成コードは型毎に多数のコードが生成される
trait objectは?Sizedだから直接は扱わずに&dynの形かBox<dyn>の形で使うことになる
&dynの形ならスタック上のみで使うことができるが元の型よりは長く生きられない制限がある
そこで例えば関数の返り値にしたい時などはヒープを使ってBox<dyn>の形にして返す
2022/02/18(金) 18:16:26.39ID:XJ022fQi
Box<T>の形ならヒープ上だけど
&Tの形ならスタック上のみで使うことができる
と言われたら、ん?ってならない?
&Tの形ならスタック上のみで使うことができる
と言われたら、ん?ってならない?
2022/02/18(金) 18:18:33.56ID:QcWsB3dM
ヒープ使わないんだったら、そりゃスタックになるが、
そもそもなにか勘違いしてない?
そもそもなにか勘違いしてない?
2022/02/18(金) 19:03:20.48ID:7ZNuwX6P
&dyn の形ならスタックで "も" 使うことができる
ってこと?
ってこと?
2022/02/19(土) 02:35:40.94ID:l5YLFJyt
dynはヒープを使わない
しかしサイズが不定
つまりdyn型の変数はない
スタック上で使う時は&dyn型の変数に入れて用いる
戻り値にしたいならBox<dyn Trait>
これはヒープ使うことになる
しかしサイズが不定
つまりdyn型の変数はない
スタック上で使う時は&dyn型の変数に入れて用いる
戻り値にしたいならBox<dyn Trait>
これはヒープ使うことになる
2022/02/19(土) 03:42:10.99ID:ukdLXHKY
(stable rustでは) dyn 型の変数はない
が正しい
が正しい
2022/02/19(土) 13:30:36.11ID:Pa/XmNxa
>>40
strはヒープを使わない
しかしサイズが不定
つまりstr型の変数はない
スタック上で使う時は&str型の変数に入れて用いる
戻り値にしたいならBox<str>
これはヒープ使うことになる
これでも
んー・・・ってならないならもういいや
strはヒープを使わない
しかしサイズが不定
つまりstr型の変数はない
スタック上で使う時は&str型の変数に入れて用いる
戻り値にしたいならBox<str>
これはヒープ使うことになる
これでも
んー・・・ってならないならもういいや
2022/02/19(土) 15:49:52.73ID:lVeS0ElI
その置き換えは無理があるんじゃないか
&strは単なる参照で&strの一部でもStringの一部でも代入できる
&dyn Traitはそれを実装する具体型を代入することで生成される
&strは単なる参照で&strの一部でもStringの一部でも代入できる
&dyn Traitはそれを実装する具体型を代入することで生成される
2022/02/19(土) 18:01:00.26ID:yRRevCPm
&dynの参照先はヒープ(例えばBoxの中身)の可能性もあるからヒープを使わないって表現は誤解を招きそう
2022/02/19(土) 18:59:15.30ID:l5YLFJyt
2022/02/19(土) 22:32:05.29ID:uI4ynUv+
>>43
&strがstrへの参照であるように
&dyn Traitもdyn Traitへ単なる参照
&strにStringを代入すればDerefがstrを生成してるように
&dyn ReadにFileを代入すればコンパイラがdyn Readを生成してる
BoxだけでなくRc<dyn Trait>とかも使えるからね
&strがstrへの参照であるように
&dyn Traitもdyn Traitへ単なる参照
&strにStringを代入すればDerefがstrを生成してるように
&dyn ReadにFileを代入すればコンパイラがdyn Readを生成してる
BoxだけでなくRc<dyn Trait>とかも使えるからね
2022/02/19(土) 23:18:16.06ID:lVeS0ElI
>>46
自己矛盾を起こしているぞ2点も
まず1点目
前者はターゲットstrでimpl Deref for String実装というコードが実際にありその枠組みに従った規定通りの操作
後者はそのような枠組みも実装コードも公開されていない操作
次に2点目
前者はStringの一部を指しているだけであり何か新たな実体を生成してそこを指しているわけではない
後者はFileとは別にvtableなどの実体を生成している
このように明白に異なる
自己矛盾を起こしているぞ2点も
まず1点目
前者はターゲットstrでimpl Deref for String実装というコードが実際にありその枠組みに従った規定通りの操作
後者はそのような枠組みも実装コードも公開されていない操作
次に2点目
前者はStringの一部を指しているだけであり何か新たな実体を生成してそこを指しているわけではない
後者はFileとは別にvtableなどの実体を生成している
このように明白に異なる
2022/02/20(日) 01:59:50.05ID:Fazun+uY
2022/02/20(日) 02:11:24.76ID:Fazun+uY
>>47
>前者はStringの一部を指しているだけであり何か新たな実体を生成してそこを指しているわけではない
>後者はFileとは別にvtableなどの実体を生成している
ああ、なるほど
trait objectが生成されるときにvtableも生成されると思ってるのか
>前者はStringの一部を指しているだけであり何か新たな実体を生成してそこを指しているわけではない
>後者はFileとは別にvtableなどの実体を生成している
ああ、なるほど
trait objectが生成されるときにvtableも生成されると思ってるのか
2022/02/20(日) 02:49:14.40ID:Q+YkyZIv
dynにキャストするときにコンパイラがfat pointerから参照させる用のvtableを生成することを指しているのでは?
2022/02/20(日) 03:20:02.69ID:Y4d5gioW
2022/02/20(日) 10:31:39.82ID:NNOlvVsy
>>50,51
vtableはtrait objectの有無に限らずtrait実装につき1つコンパイル時に作成されそれが共有して使われる
vtableを指すtrait objectも実行時じゃなくコンパイル時に作成される
実行時にはvtable経由のダイナミックディスパッチが発生するだけ
vtableはtrait objectの有無に限らずtrait実装につき1つコンパイル時に作成されそれが共有して使われる
vtableを指すtrait objectも実行時じゃなくコンパイル時に作成される
実行時にはvtable経由のダイナミックディスパッチが発生するだけ
2022/02/20(日) 11:23:51.17ID:Q+YkyZIv
>>52
そうか、crate内で静的ディスパッチしかしてなくても他crateからtrait objectとして使われる場合もあるから常にvtableは生成されるのね
ちなみに、object safeでないtraitについては生成されない (できない) よね?
そうか、crate内で静的ディスパッチしかしてなくても他crateからtrait objectとして使われる場合もあるから常にvtableは生成されるのね
ちなみに、object safeでないtraitについては生成されない (できない) よね?
2022/02/20(日) 13:54:46.64ID:xQDNRCh/
Rustって関数のデフォルト引数ないの?
2022/02/20(日) 14:48:11.68ID:MpUmJclU
>>53
trait objectとして使われなくても常にvtableが作成されるかどうかはコンパイラの最適化の話だからここでは関係ないよね
実際のところはdylibじゃなければコンパイル時に使われないことがはっきりしてるはずだから作られないと思うけど
trait objectとして使われなくても常にvtableが作成されるかどうかはコンパイラの最適化の話だからここでは関係ないよね
実際のところはdylibじゃなければコンパイル時に使われないことがはっきりしてるはずだから作られないと思うけど
2022/02/20(日) 17:48:45.70ID:Q+YkyZIv
>>55
コンパイル時じゃなくてリンク時の最適化の話じゃないの
オブジェクトファイルには常にvtable埋め込まれてるのかと
それとも dyn Trait を使った側のcrateのオブジェクトファイルにvtableは埋め込まれる?
コンパイル時じゃなくてリンク時の最適化の話じゃないの
オブジェクトファイルには常にvtable埋め込まれてるのかと
それとも dyn Trait を使った側のcrateのオブジェクトファイルにvtableは埋め込まれる?
2022/02/20(日) 22:19:41.32ID:uSEnVnLU
>>51
>> vtable自体は型とtraitのペアで静的に確定するものでありコンパイル時に生成
>>52
>> vtableはtrait objectの有無に限らずtrait実装につき1つコンパイル時に作成
この件だがコンパイラのソースを見ると
必要となる型の分だけコンパイル時にvtableを作成してるよな
https://github.com/rust-lang/rust/blob/stable/compiler/rustc_codegen_ssa/src/meth.rs#L53
>> vtable自体は型とtraitのペアで静的に確定するものでありコンパイル時に生成
>>52
>> vtableはtrait objectの有無に限らずtrait実装につき1つコンパイル時に作成
この件だがコンパイラのソースを見ると
必要となる型の分だけコンパイル時にvtableを作成してるよな
https://github.com/rust-lang/rust/blob/stable/compiler/rustc_codegen_ssa/src/meth.rs#L53
2022/02/21(月) 00:37:14.94ID:Vy+crfrM
crateあたり同一traitのvtableは最大一つ生成されるということかな
2022/02/21(月) 00:58:29.74ID:hWQuQvUr
同一traitが複数の型で実装されてたらその型ごとに作られるはず
60デフォルトの名無しさん
2022/02/21(月) 17:43:56.41ID:LC1rF3os 各型毎にtrait objectやvtableはこういう構造になっている
let mut stdin: std::io::Stdin = std::io::stdin();
let addr_stdin = addr!(stdin); // &mut借用する前にアドレスを得ておく
let dyn_stdin: &mut dyn std::io::Read = &mut stdin; // ここで dyn Readのtrait object作成
assert_eq!(val!(addr!(dyn_stdin), 0), addr_stdin); // 前半は元のstdinを指している
// assert_eq!(val!(addr!(dyn_stdin), 1), 【Stdin用のvtable】); // 後半はStdin用vtableをを指している
assert_eq!(val!(val!(addr!(dyn_stdin), 1), 3), <std::io::Stdin as std::io::Read>::read as usize);
assert_eq!(val!(val!(addr!(dyn_stdin), 1), 4), <std::io::Stdin as std::io::Read>::read_vectored as usize);
別の型でも同じようにdyn Read作成
let mut file: std::fs::File = std::fs::File::open("/dev/null").unwrap();
let addr_file = addr!(file);
let dyn_file: &mut dyn std::io::Read = &mut file; // trait object作成
assert_eq!(val!(addr!(dyn_file), 0), addr_file); // 前半は元のfileを指している
// assert_eq!(val!(addr!(dyn_stdin), 1), 【File用のvtable】); // 後半はFile用vtableをを指している
assert_eq!(val!(val!(addr!(dyn_file), 1), 3), <std::fs::File as std::io::Read>::read as usize);
assert_eq!(val!(val!(addr!(dyn_file), 1), 4), <std::fs::File as std::io::Read>::read_vectored as usize);
上述Stdinの時と同じ位置にFile用のread()やread_vectored()がvtableに入っていることがわかる
したがって>>59や>>51が正しいと思う
各trait毎にvtableのメソッドの位置が決まり
そのtraitを実装する各型毎にvtableが作成される
let mut stdin: std::io::Stdin = std::io::stdin();
let addr_stdin = addr!(stdin); // &mut借用する前にアドレスを得ておく
let dyn_stdin: &mut dyn std::io::Read = &mut stdin; // ここで dyn Readのtrait object作成
assert_eq!(val!(addr!(dyn_stdin), 0), addr_stdin); // 前半は元のstdinを指している
// assert_eq!(val!(addr!(dyn_stdin), 1), 【Stdin用のvtable】); // 後半はStdin用vtableをを指している
assert_eq!(val!(val!(addr!(dyn_stdin), 1), 3), <std::io::Stdin as std::io::Read>::read as usize);
assert_eq!(val!(val!(addr!(dyn_stdin), 1), 4), <std::io::Stdin as std::io::Read>::read_vectored as usize);
別の型でも同じようにdyn Read作成
let mut file: std::fs::File = std::fs::File::open("/dev/null").unwrap();
let addr_file = addr!(file);
let dyn_file: &mut dyn std::io::Read = &mut file; // trait object作成
assert_eq!(val!(addr!(dyn_file), 0), addr_file); // 前半は元のfileを指している
// assert_eq!(val!(addr!(dyn_stdin), 1), 【File用のvtable】); // 後半はFile用vtableをを指している
assert_eq!(val!(val!(addr!(dyn_file), 1), 3), <std::fs::File as std::io::Read>::read as usize);
assert_eq!(val!(val!(addr!(dyn_file), 1), 4), <std::fs::File as std::io::Read>::read_vectored as usize);
上述Stdinの時と同じ位置にFile用のread()やread_vectored()がvtableに入っていることがわかる
したがって>>59や>>51が正しいと思う
各trait毎にvtableのメソッドの位置が決まり
そのtraitを実装する各型毎にvtableが作成される
2022/02/21(月) 18:18:27.01ID:Vy+crfrM
traitをimplした型が違ったら対応するfnの中身も違うので
同じtraitでも実装された型ごとに違うvtable作らなきゃいけないのは確かに当然か
>>60
異なるcrateからtrait object生成した場合にvtableは同じアドレスのものになるの?
それとも、異なるものになるの?
同じtraitでも実装された型ごとに違うvtable作らなきゃいけないのは確かに当然か
>>60
異なるcrateからtrait object生成した場合にvtableは同じアドレスのものになるの?
それとも、異なるものになるの?
2022/02/21(月) 23:56:22.93ID:1opwFCgw
>>57
「trait objectを使うようなコードが一切存在しなくても」vtableが作られると言いたかったわけではないんだが書き方が悪かったね
「trait objectを使うようなコードが一切存在しなくても」vtableが作られると言いたかったわけではないんだが書き方が悪かったね
2022/02/22(火) 00:04:11.51ID:DlNWIu8c
vtable自体はデバッグビルドのasmやllvm-irで確認できるよ
例えばxという名前のメソッド1つだけ持つFooトレイトのi32実装ならこんな形でvtableが出力される
.quad core::ptr::drop_in_place<i32>
.asciz "¥004¥000¥000¥000¥000¥000¥000¥000¥004¥000¥000¥000¥000¥000¥000"
.quad <i32 as playground::Foo>::x
例えばxという名前のメソッド1つだけ持つFooトレイトのi32実装ならこんな形でvtableが出力される
.quad core::ptr::drop_in_place<i32>
.asciz "¥004¥000¥000¥000¥000¥000¥000¥000¥004¥000¥000¥000¥000¥000¥000"
.quad <i32 as playground::Foo>::x
2022/02/22(火) 11:55:50.79ID:M+NPwtu0
2022/02/22(火) 12:24:58.23ID:M+NPwtu0
違う型のvtableがmergeされることもあるみたい
https://rust-lang.github.io/rust-clippy/master/#vtable_address_comparisons
https://rust-lang.github.io/rust-clippy/master/#vtable_address_comparisons
2022/02/22(火) 12:36:19.01ID:Uj7UhjXB
2022/02/22(火) 14:56:23.72ID:S7d5HFwX
>>60
もう少しvtableの情報を詳細にした
let mut file: std::fs::File = std::fs::File::open("/dev/null").unwrap();
let addr_file = addr!(file);
let dyn_file: &mut dyn std::io::Read = &mut file;
という状況で以下が成立
assert_eq!(val!(addr!(dyn_file), 0), addr_file);
let vtable_file = val!(addr!(dyn_file), 1);
assert_eq!(val!(vtable_file, 0), std::ptr::drop_in_place::<std::fs::File> as usize);
assert_eq!(val!(vtable_file, 1), std::mem::size_of::<std::fs::File>());
assert_eq!(val!(vtable_file, 2), std::mem::align_of::<std::fs::File>());
assert_eq!(val!(vtable_file, 3), <std::fs::File as std::io::Read>::read as usize);
assert_eq!(val!(vtable_file, 4), <std::fs::File as std::io::Read>::read_vectored as usize);
つまり型情報が消失したdynにおいてもこのvtableさえ保持していれば正しくトレイトメソッドやデストラクタを呼び出せる
>>65
そのコードだと比較しようとしているのはvtableやそのアドレスではなく
上述コードでのdyn_fileのアドレスを比較しているだけなのでそもそも前提が謎だな
さらにvtableの内容は各型に完全に依存しているからmergeの意味もよくわからない
もう少しvtableの情報を詳細にした
let mut file: std::fs::File = std::fs::File::open("/dev/null").unwrap();
let addr_file = addr!(file);
let dyn_file: &mut dyn std::io::Read = &mut file;
という状況で以下が成立
assert_eq!(val!(addr!(dyn_file), 0), addr_file);
let vtable_file = val!(addr!(dyn_file), 1);
assert_eq!(val!(vtable_file, 0), std::ptr::drop_in_place::<std::fs::File> as usize);
assert_eq!(val!(vtable_file, 1), std::mem::size_of::<std::fs::File>());
assert_eq!(val!(vtable_file, 2), std::mem::align_of::<std::fs::File>());
assert_eq!(val!(vtable_file, 3), <std::fs::File as std::io::Read>::read as usize);
assert_eq!(val!(vtable_file, 4), <std::fs::File as std::io::Read>::read_vectored as usize);
つまり型情報が消失したdynにおいてもこのvtableさえ保持していれば正しくトレイトメソッドやデストラクタを呼び出せる
>>65
そのコードだと比較しようとしているのはvtableやそのアドレスではなく
上述コードでのdyn_fileのアドレスを比較しているだけなのでそもそも前提が謎だな
さらにvtableの内容は各型に完全に依存しているからmergeの意味もよくわからない
2022/02/22(火) 15:27:07.33ID:Uj7UhjXB
空traitなんかは異なる型同士でvtable使い回しできるのでは
あとは全associated fnにデフォルト実装が与えられていて中身が全く同じものとか
いずれにせよLLVMがよしなに最適化してくれるとかなのでは?
あとは全associated fnにデフォルト実装が与えられていて中身が全く同じものとか
いずれにせよLLVMがよしなに最適化してくれるとかなのでは?
2022/02/22(火) 17:06:00.72ID:S7d5HFwX
vtableにはデストラクタも乗ってるようだけどそれも必要ない場合あるもんな
>>67の状況も今後実装が変わったり最適化で消えたり色々ありうるわけだ
いずれにせよ我々は興味本位で語り合ってるだけであり
このあたりの非公開の仕様に依存したコードを書いてはいけないしな
>>67の状況も今後実装が変わったり最適化で消えたり色々ありうるわけだ
いずれにせよ我々は興味本位で語り合ってるだけであり
このあたりの非公開の仕様に依存したコードを書いてはいけないしな
2022/02/22(火) 23:08:55.74ID:uChpKE+n
>>67
>上述コードでのdyn_fileのアドレスを比較しているだけなのでそもそも前提が謎だな
Rc::ptr_eqで単純に比較するとfat pointer内のdataへのpointerとvtableへのpointerの両方が一致してるかのテストになる
>さらにvtableの内容は各型に完全に依存しているからmergeの意味もよくわからない
わかりやすいのは&Tと&mut Tのように可視性のみ違う場合
>上述コードでのdyn_fileのアドレスを比較しているだけなのでそもそも前提が謎だな
Rc::ptr_eqで単純に比較するとfat pointer内のdataへのpointerとvtableへのpointerの両方が一致してるかのテストになる
>さらにvtableの内容は各型に完全に依存しているからmergeの意味もよくわからない
わかりやすいのは&Tと&mut Tのように可視性のみ違う場合
2022/02/22(火) 23:17:56.21ID:WirMN8li
2022/02/22(火) 23:33:33.79ID:uChpKE+n
2022/02/22(火) 23:44:43.85ID:uChpKE+n
>>71
std::ptr::eqでdataへのpointerを比較すれば保証されると思うよ
std::ptr::eqでdataへのpointerを比較すれば保証されると思うよ
2022/02/23(水) 08:40:05.57ID:jDTq074F
プロジェクトのディレクトリの外から
$ cargo run
するときってどうやってプロジェクト (ディレクトリ) を指定するの?
$ cargo run
するときってどうやってプロジェクト (ディレクトリ) を指定するの?
2022/02/23(水) 10:36:44.63ID:gSf/7C4x
2022/02/23(水) 15:08:57.81ID:d/vifWyJ
>>74
用途が違うかもしれんがworkspace配下からなら-p <package-name>で指定できる
用途が違うかもしれんがworkspace配下からなら-p <package-name>で指定できる
2022/02/23(水) 23:58:29.92ID:EqZ7VJsi
>>70
vtableがmergeされるのかどうか
trait定義methodの定数返しと最適化されやすいようにして
さらに &T と &mut T でやってみたがtableは別々になった
まず最初の原因はvtable最初の要素である以下が成立していないためとわかった
assert_eq!(std::ptr::drop_in_place::<&i32> as usize, std::ptr::drop_in_place::<&mut i32> as usize);
ところが--releaseにすると上記は成立するようになった
同様にtrait定義methodも--releaseにすると同じアドレスとなった
つまりこういう実験において--releaseオプションは必須
そしてvtableの内容は全て完全に一致
しかしvtableのアドレス(格納場所)は異なり別々のvtableのままであった
vtableがmergeされるのかどうか
trait定義methodの定数返しと最適化されやすいようにして
さらに &T と &mut T でやってみたがtableは別々になった
まず最初の原因はvtable最初の要素である以下が成立していないためとわかった
assert_eq!(std::ptr::drop_in_place::<&i32> as usize, std::ptr::drop_in_place::<&mut i32> as usize);
ところが--releaseにすると上記は成立するようになった
同様にtrait定義methodも--releaseにすると同じアドレスとなった
つまりこういう実験において--releaseオプションは必須
そしてvtableの内容は全て完全に一致
しかしvtableのアドレス(格納場所)は異なり別々のvtableのままであった
2022/02/24(木) 00:46:54.35ID:rseQo+7Q
LLVMの最適化で何が行われるかrust側では保証できないから >>65 みたいに同一性について保証しないって仕様になっているんだろうね
79デフォルトの名無しさん
2022/02/24(木) 00:52:17.43ID:8HElZ5AU そういえばRustってC++とかFortranみたいに最適化で結果変わる可能性ってあるの?
2022/02/24(木) 00:56:53.49ID:rseQo+7Q
>>77 がその結果の変わる一例では、ってことではない?
81デフォルトの名無しさん
2022/02/24(木) 00:59:33.72ID:8HElZ5AU >>77は内部構造が変わるという話で出力が変わるという話ではないと思っていた
2022/02/24(木) 01:53:13.93ID:9O+r6lMK
>>79
Rustは他の言語と違い、UB (undefined behavior)すなわち未定義動作を基本的に起こさないように安全に設計されている
最適化オプションの有無でもその点は大丈夫
もちろん念のためだが、入力が異なれば結果は変わるし、非同期の実行タイミングは当然保証されないから実行順序に依存するコードは結果が変わり得る
そういうことでないならば結果は同じになる
ちなみにvtableの件は仕様が公開すらされていない内部情報の話
しかもそこに収容される関数のアドレスの値やvtableのアドレスの値というプログラマーが全く気にする必要ない話
だからこれらは変化してももちろん良くてそれを承知の上で盛り上がってるだけ
Rustは他の言語と違い、UB (undefined behavior)すなわち未定義動作を基本的に起こさないように安全に設計されている
最適化オプションの有無でもその点は大丈夫
もちろん念のためだが、入力が異なれば結果は変わるし、非同期の実行タイミングは当然保証されないから実行順序に依存するコードは結果が変わり得る
そういうことでないならば結果は同じになる
ちなみにvtableの件は仕様が公開すらされていない内部情報の話
しかもそこに収容される関数のアドレスの値やvtableのアドレスの値というプログラマーが全く気にする必要ない話
だからこれらは変化してももちろん良くてそれを承知の上で盛り上がってるだけ
83デフォルトの名無しさん
2022/02/24(木) 01:56:10.31ID:8HElZ5AU >>82
よかった。安心したわ。ありがとう
よかった。安心したわ。ありがとう
2022/02/24(木) 14:04:31.52ID:J4Zng4Gd
vtableの話は元々のスタックやヒープの話と関係あったの?
2022/02/24(木) 14:36:03.44ID:rseQo+7Q
関係ないけどスタックやヒープの話よりも面白かった
2022/02/25(金) 09:31:23.23ID:oVhsjzPL
ついに期待のRust 1.59がリリース!
2022/02/25(金) 09:56:57.35ID:Ttq2k6xT
>>86
なにか目玉機能あるの?
なにか目玉機能あるの?
2022/02/25(金) 11:13:21.04ID:q7+lZsL0
asm!とdestructuring assignmentかな
2022/02/25(金) 12:42:45.63ID:eJN5yWKN
来たね
2022/02/25(金) 15:06:17.84ID:5XzVm2I+
inline asm安定化は嬉しい、stableでベアメタルやりやすくなるかも
2022/02/25(金) 16:04:22.84ID:kxjR7eze
2022/02/25(金) 17:28:20.31ID:kxjR7eze
同じやつかもしれんが、スレ違いの指摘を聞かない馬鹿3名引き取ってくれ
ID:u7rOKKj6
ID:iu2arc+w
ID:aDhOSI3t
ID:u7rOKKj6
ID:iu2arc+w
ID:aDhOSI3t
2022/02/25(金) 17:31:49.95ID:hSBNElz8
お膣毛
2022/02/25(金) 17:39:52.83ID:q7+lZsL0
rustのバージョンごとのリリース予定機能ってどこかにまとまってるの?
betaに入ったものはだいたいそのままstableになるから事前にどの機能が来るのか分かると思うんだが
いつもstableリリースのブログ投稿で知るので、もっと早めに知れると嬉しい
betaに入ったものはだいたいそのままstableになるから事前にどの機能が来るのか分かると思うんだが
いつもstableリリースのブログ投稿で知るので、もっと早めに知れると嬉しい
2022/02/25(金) 18:25:23.29ID:clIznFGF
Rust コンパイラのリリースサイクルは六週間という時間で区切ってるから
その時点で確定してるものが入るって感じじゃないの。
次のリリースまでにこれとこれを……というようなマイルストーン方式ではない。
その時点で確定してるものが入るって感じじゃないの。
次のリリースまでにこれとこれを……というようなマイルストーン方式ではない。
2022/02/25(金) 18:45:09.48ID:q7+lZsL0
最近12週間でnightly(master)でstabilizeされた機能一覧とか
最近6週間でbetaに入った機能一覧を知る方法ない?って意図だった
最近6週間でbetaに入った機能一覧を知る方法ない?って意図だった
2022/02/25(金) 18:59:15.48ID:qITSG3O9
Githubのマイルストーン見ればいいんじゃない?
例えば1.60.0だとこれが入る予定なはず
https://github.com/rust-lang/rust/milestone/90?closed=1
例えば1.60.0だとこれが入る予定なはず
https://github.com/rust-lang/rust/milestone/90?closed=1
2022/02/25(金) 19:27:57.07ID:q7+lZsL0
なるほどmilestoneがあったか
relnotesラベルで絞り込むといい感じだ
ありがとう
https://github.com/rust-lang/rust/issues?q=milestone%3A1.60.0+label%3Arelnotes
relnotesラベルで絞り込むといい感じだ
ありがとう
https://github.com/rust-lang/rust/issues?q=milestone%3A1.60.0+label%3Arelnotes
2022/02/25(金) 21:16:51.47ID:kxjR7eze
100デフォルトの名無しさん
2022/03/02(水) 12:22:44.66ID:Pojz7Ujc Electronの代替を目指す軽量なRust製フレームワーク「Tauri」、リリース候補版に到達
https://www.publickey1.jp/blog/22/electronrusttauri.html
Electronの優れた特徴を備えつつ、よりメモリ消費量が小さくファイルサイズもコンパクトで、高いセキュリティを備え、柔軟なライセンスを実現しようと開発されたのが「Tauri」です。
GitHubにはElectronとの比較表が示されています。それによるとLinux版のインストールサイズがElectronで52.1MBのところ、Tauriは10分の1以下のわずか3.1MB。同じくLinux版でのメモリ消費量はElectronが462MBのところ、Tauriは半分以下の180MBとなっています。
起動時間もElectronの0.80秒に対してTauriは0.39秒です。
https://www.publickey1.jp/blog/22/electronrusttauri.html
Electronの優れた特徴を備えつつ、よりメモリ消費量が小さくファイルサイズもコンパクトで、高いセキュリティを備え、柔軟なライセンスを実現しようと開発されたのが「Tauri」です。
GitHubにはElectronとの比較表が示されています。それによるとLinux版のインストールサイズがElectronで52.1MBのところ、Tauriは10分の1以下のわずか3.1MB。同じくLinux版でのメモリ消費量はElectronが462MBのところ、Tauriは半分以下の180MBとなっています。
起動時間もElectronの0.80秒に対してTauriは0.39秒です。
101デフォルトの名無しさん
2022/03/02(水) 13:09:17.24ID:f02FsuUz モバイル版も予定されてるとなるとFlutterにも似てるかな
あっちはモバイルベースのフレームワークだけど
あっちはモバイルベースのフレームワークだけど
102デフォルトの名無しさん
2022/03/02(水) 16:28:42.01ID:GthnxnyS rustで複数のプロセスで「共有メモリ」したい場合ってどうすればいいの?
103デフォルトの名無しさん
2022/03/02(水) 16:53:15.47ID:Bz8WDQhq プロセス間だとCと大して変わらないと思う
libcのmmapとかでアドレスに共有ファイルを割り当ててそのポインタをBoxもどきで包む
Drop時にfreeじゃなくmunmapするBoxっぽい別の型が必要でプロセス間のロックとか考えるともっと面倒くさい
mmapでcrate検索すれば使えるのがあるかもしれない
libcのmmapとかでアドレスに共有ファイルを割り当ててそのポインタをBoxもどきで包む
Drop時にfreeじゃなくmunmapするBoxっぽい別の型が必要でプロセス間のロックとか考えるともっと面倒くさい
mmapでcrate検索すれば使えるのがあるかもしれない
104デフォルトの名無しさん
2022/03/02(水) 17:43:29.63ID:uPKvDIET 基本的には >>103 の言うとおり C と変わらないと思う
shared_memoryというLinuxとWindowsで使えるクロスプラットフォームなcrateもあるみたいだね
ただプロセス間でメモリを共有する場合に複数プロセスから同一領域に対して &mut 参照を作っちゃうと UB にならないかは気になる
shared_memoryというLinuxとWindowsで使えるクロスプラットフォームなcrateもあるみたいだね
ただプロセス間でメモリを共有する場合に複数プロセスから同一領域に対して &mut 参照を作っちゃうと UB にならないかは気になる
105デフォルトの名無しさん
2022/03/03(木) 05:15:49.21ID:CxPtyFsv106デフォルトの名無しさん
2022/03/03(木) 05:38:31.20ID:uxaiIIsi >>105
かなり違うよ?
かなり違うよ?
107デフォルトの名無しさん
2022/03/03(木) 07:53:58.47ID:XBGsBJa3 むしろ、rustでプロセス間通信をする場合に相性が良いのは何か、というのが本質では無いだろうか?
プロセス間共有メモリをrust的に安全になるように包むことは可能なのか?
パイプやソケットの再実装にならないか?
プロセス間共有メモリをrust的に安全になるように包むことは可能なのか?
パイプやソケットの再実装にならないか?
108デフォルトの名無しさん
2022/03/03(木) 08:16:43.34ID:yxmIabOi 本当に共有メモリが必要なのか?って所だよな
ベアメタル開発時のハードウェアみたいに必須のケースもあるけど
ベアメタル開発時のハードウェアみたいに必須のケースもあるけど
109デフォルトの名無しさん
2022/03/03(木) 08:44:34.78ID:y+9ANsMY メッセージキューのほうが安全かね。
速度と手間は犠牲になりそうだけど。
速度と手間は犠牲になりそうだけど。
110デフォルトの名無しさん
2022/03/03(木) 09:15:37.98ID:yKQiCvPK どういう問題を解決したいかという文脈抜きに
どういう手段がいいかを論じても意味ないよ
いわゆるXY problem
どういう手段がいいかを論じても意味ないよ
いわゆるXY problem
111デフォルトの名無しさん
2022/03/03(木) 09:18:31.12ID:QJbsAkty >>107
共有メモリをミューテクスで排他制御するならロックの取得/解放をメモリの取得/解放と同等に扱えるような気はするが
共有メモリをミューテクスで排他制御するならロックの取得/解放をメモリの取得/解放と同等に扱えるような気はするが
112デフォルトの名無しさん
2022/03/03(木) 10:18:45.28ID:sMoqT2I4 volatileアクセスするのが自然なんじゃねーの。
113デフォルトの名無しさん
2022/03/03(木) 16:55:17.18ID:/KrGueou >>112
volataileはプロセス間のリソース共有とは概念的には別の話。
volataileはプロセス間のリソース共有とは概念的には別の話。
114デフォルトの名無しさん
2022/03/03(木) 17:16:17.86ID:P+eyfKB6 少なくともCでは
CON02-C. volatile を同期用プリミティブとして使用しない
ttps://www.jpcert.or.jp/sc-rules/c-con02-c.html
だけど、Rustは同期が保証されるんだっけ?
CON02-C. volatile を同期用プリミティブとして使用しない
ttps://www.jpcert.or.jp/sc-rules/c-con02-c.html
だけど、Rustは同期が保証されるんだっけ?
115デフォルトの名無しさん
2022/03/03(木) 19:04:46.11ID:XBGsBJa3 それはマルチスレッドの話でしょ?
116デフォルトの名無しさん
2022/03/03(木) 19:15:45.62ID:hTxF5AaQ 全ての共有メモリのページアクセスに対して割込みをかけてるならそういう実装も可能だろうけど、現実的には考えにくいだろうw
アホなこと考える前に自分でコード読めよw
アホなこと考える前に自分でコード読めよw
117デフォルトの名無しさん
2022/03/03(木) 19:22:14.52ID:Rf6M0oqn118デフォルトの名無しさん
2022/03/04(金) 11:29:49.34ID:gcV9MtLz >>117
根拠はないけどできると思うよ
根拠はないけどできると思うよ
■ このスレッドは過去ログ倉庫に格納されています
ニュース
- 【赤坂ライブハウス刺傷】逃走していた自衛官の男(43)を殺人未遂の疑いで逮捕 警視庁 被害女性とは知人関係 [Ailuropoda melanoleuca★]
- 【千葉】コンビニに尿入りペットボトル並べた疑い、26歳男「むしゃくしゃして」…購入した客が飲もうとしたところ臭いに違和感 [ぐれ★]
- 中国官製報道「日本経済はもう持たない」にネット民ツッコミ「ニュースだけ見てたら日本はもう百回くらい爆発してる」 [1ゲットロボ★]
- 植田日銀総裁 「円安進行が物価高を起こしている」 ★4 [お断り★]
- 【STARTO ENTERTAINMENT】timelesz、メンバーの不適切言動を謝罪「不用意かつモラルに反した発言であった」 全員の署名入りでコメント [Ailuropoda melanoleuca★]
- 【硬貨】500円だと思ったら「500ウォンが入っていた」価値は約10分の1 全国で飲食店などで“500ウォントラブル”相次いで報告 [ぐれ★]
- 【神奈川新聞】「暇空茜」を県警追送検 [746833765]
- コンビニでラーメンとおにぎり買うとラーメン温めてる間におにぎり食っちゃうよね
- ハムエッグ派VSベーコンエッグ派
- 小泉進次郎防衛相「日本の国防の崇高な使命は愛国心が基盤となっている」ネトウヨ歓喜 [165981677]
- 男子あるある
- 冬眠中のクマの巣穴の出口を何らかの手段で密閉したら
