Rust part9

■ このスレッドは過去ログ倉庫に格納されています
2020/08/23(日) 01:07:35.52ID:MgEpWwVh
Mozilla発のRust言語のスレ

公式
https://www.rust-lang.org/
https://blog.rust-lang.org/
https://github.com/rust-lang/rust

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

前スレ
Rust part8
https://mevius.5ch.net/test/read.cgi/tech/1579834072/
2020/12/25(金) 04:00:24.23ID:wGSzow97
糖質に構ってはいけません
2020/12/25(金) 07:45:07.16ID:0J2Xi2Rb
>>483
サンプル数1(自分自身)で100%という調査結果があるんだろう
2020/12/25(金) 13:26:59.56ID:8LlCCPCm
>>485
なんかそういうデータがあるんですか?
2020/12/25(金) 19:42:11.03ID:mWI3ilc1
>>486
サンプル数1(自分自身)で100%という調査結果があるんだろう
488デフォルトの名無しさん
垢版 |
2020/12/26(土) 02:24:44.32ID:xFdgYNcK
結局C言語最強?
ならZetZも盛り上がる可能性ある?
https://www.infoq.com/jp/news/2020/05/zz-formal-verified-c-dialect/
2020/12/26(土) 09:20:22.55ID:QvgSObSy
>>488
D言語でいう契約を静的に検証できるみたいな感じかな? いいね
2020/12/26(土) 10:09:44.78ID:q2RopqqH
いいね
盛り上がりはしないとは思うけど…
2020/12/26(土) 11:37:01.29ID:Gj+PzIiF
OSS界隈で盛り上がる感じはしないけど
自動車とかはそっちのほうが見込みありそう
2020/12/26(土) 13:21:33.22ID:qrKCtheG
Vecのget()メソッドがi32とかも受け取ってくれればよかったのにとよく思う
結局、負方面については自分でインデックス内か検証しないといけないし
2020/12/26(土) 15:29:03.87ID:PUwCvC/R
extension traitとかnewtypeで拡張すればいいんでは?

https://play.rust-lang.org/?version=stable&;mode=debug&edition=2018&gist=1b575c52e97e24c3ae345e945ec7dbbd
2020/12/26(土) 16:18:17.43ID:qrKCtheG
はえ〜ありがとうございます!
これ標準ライブラリに採用してほしい(我儘)
2020/12/26(土) 20:14:31.56ID:q2RopqqH
貴様だってnewtypeだろうに!
2020/12/27(日) 03:56:05.63ID:iVarltSe
小賢しいことを少年が言うのか!
2020/12/27(日) 04:20:16.63ID:a9FVrfkC
ガンダムハラスメントはやめてください
2020/12/27(日) 13:57:50.83ID:gMdNxh6H
たとえばこのように書いたときに

fn zero_bytes<T :Sized>() -> [u8; std::mem::size_of::<T>()] {
[0u8; std::mem::size_of::<T>()]
}

エラーとして

the size for values of type `T` cannot be known at compilation time

となってしまいます。
型の大きさに依存した配列を生成するには (実際にはコンパイル時に確定するはずでも)
Vec などを利用するしか仕方がないのでしょうか?
2020/12/27(日) 16:28:27.67ID:VS6+Jx70
>>498
配列の要素数はconstじゃないとだめだからジェネリックには今のところできないみたい
どこかで型を書かないと

const SIZE: usize = std::mem::size_of::<i32>();
let foo = [0u8; SIZE];

https://github.com/rust-lang/rust/issues/43408
2020/12/27(日) 19:25:21.46ID:UNA5PysG
const fn, lazy_static のあたりは他の言語やってた人にはわかりづらいよな
2020/12/27(日) 20:30:38.54ID:iVarltSe
コンパイル時計算は最近の言語じゃ普通だけどな。
コンパイル時リフレクション使える言語も増えたし。

>>498
ttps://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=e09bdfe4323f597481eae11421777cc3

ttps://rust-lang.github.io/rfcs/2000-const-generics.html
ttps://github.com/rust-lang/rust/issues/44580

一時間前にマージされたばかりで1.51.0のマイルストーン完了したからそのうちnightlyに来る。
ttps://github.com/rust-lang/rust/pull/79135

edition 2021には間に合うんじゃないの?
2020/12/28(月) 02:45:21.79ID:UcUcH/pf
Java では、class Foo{ Bar bar; } で済むところが、Rustでは以下の様な選択肢に悩まされる。

struct Foo { bar: Bar }
struct Foo<'a> { bar: &'a Bar }
struct Foo<'a> { bar: &'a mut Bar }
struct Foo { bar: Box<Bar> }
struct Foo { bar: Rc<Bar> }
struct Foo { bar: Arc<Bar> }

そして特に、'aの部分やBox, Rc, Arcの取り扱いやRcとArcの違いなどに悩まされる
ことになる。
これに加えて実践的にはOption, RefCellなどを何重にも組み合わせて使うことが必要となり
正しく理解するのはC++より遙かに難しい。
2020/12/28(月) 02:52:18.54ID:UcUcH/pf
>>502
ちなみに、plain Cの場合、
struct Foo { struct Bar *bar; }; // (1)
で済む。C++の場合、もちろんこれでもいけるが、
class Foo { Bar *bar; }; // (2)
1つでも特に問題ない。
uniqu_ptr<Bar>やshared_ptr<Bar>
も使えるが (2)で出来ないことは特に無いし、難しくも無く
Javaのclass Foo{ Bar bar; }
と使い勝手も余り変わらない。
違うのはbarが不要になった時に自分で deleteするだけで、
多くの場合、
class Foo {
 Bar *bar;
 Foo() { bar = NULL; }
 ~Foo() { delete bar; }
};
と書けばよいだけで、これはパターンなので丸覚えでも良いし、意味の理解も
難しくも無く、悩むことも無い。
それに比べればRustが如何に複雑なことか。
2020/12/28(月) 02:57:07.20ID:UcUcH/pf
[補足]
C++の場合も、
class Foo { Bar *bar; }; // (1)
class Foo { unique_ptr<Bar> bar; }; // (2)
class Foo { shared_ptr<Bar> bar; }; // (3)
の選択肢は有るには有るが、常に(1)を使ってもコンパイルエラーに悩まされる
事はないし、できないこともなく、特に危険でもない。
ところがRustの場合、状況に応じて>>502のどれか一つしか選択できない
ことが多く、柔軟性に乏しい。
プログラムに僅かな変更があったときに、C++の場合、(1)なら修正が全く
必要がないが、Rustの場合は>>502のうちのどれかからどれかに修正しなくては
ならないことが多い。
2020/12/28(月) 03:21:57.08ID:UcUcH/pf
https://matklad.github.io/2020/09/20/why-not-rust.html
「Rust lacks an official specification. The reference is a work in progress,
and does not yet document all the fine implementation details.」
Rustは公式の使用が欠如している。
リファレンスマニュアルの作成は発展途上中(作成中、作業中、進展中)で、
しっかりした実装の詳細を全てドキュメント化してはいない。

Rustのコンパイル時間がとても長いことを直後に指摘した上で、
「A program written in a slower to run but faster to compile programming
language can be faster to run because the programmer
will have more time to optimize!」
実行速度が遅いがコンパイルが速い言語で書かれたプログラムは、
実際には速く実行できるようになる。
なぜなら、プログラマが最適化する時間をより沢山得ることが出来るためだ。
2020/12/28(月) 03:37:08.29ID:UcUcH/pf
現実のプログラムでは、CやC++とRustのプログラムを連携しなければならない
ということと指摘した上で、Cargoがそれを難しくしているかも知れないことを
指摘している:

「One specific gotcha is that Cargo’s opinionated world view
(which is a blessing for pure Rust projects) might make
it harder to integrate with a bigger build system.」

具体的には、Cargo主張する世界観(これは純粋なRustプロジェクトにとっては
幸いなことです)が、より大きなビルドシステムとの統合を
難しくしているかもしれないということです。
507デフォルトの名無しさん
垢版 |
2020/12/28(月) 03:48:47.51ID:UcUcH/pf
「First, there’s no definition of Rust memory model, so it is impossible to
formally check if a given unsafe block is valid or not. There’s informal
definition of “things rustc does or might rely on” and in in-progress
runtime verifier, but the actual model is in flux. So there might be some
unsafe code somewhere which works OK in practice today, might be
declared invalid tomorrow, and broken by a new compiler optimization
next year.」

第一に、Rustのメモリモデルの定義がないので、与えられた安全でないブロック
が有効かどうかを正式にチェックすることができません。非公式な定義として、
"rustc が行う、または依存しているかもしれないこと "と、進行中のランタイム
ベリファイアがありますが、実際のモデルは流動的です。つまり、どこかに安全
でないコードがあるかもしれませんが、今日は問題なく動作していても、明日
には無効と宣言され、来年の新しいコンパイラの最適化で壊れてしまうかも
しれません。
2020/12/28(月) 03:52:06.86ID:UcUcH/pf
Second, there’s also an observation that unsafe blocks are not, in fact, modular.
Sufficiently powerful unsafe blocks can, in effect, extend the language. Two such
extensions might be fine in isolation, but lead to undefined behavior if used
simultaneously: Observational equivalence and unsafe code.

第二に、安全でないブロックは実際にはモジュール化されていないという観察もあります。
十分に強力な安全でないブロックは、事実上、言語を拡張することができます。
そのような2つの拡張は単独では問題ないかもしれませんが、同時に使用されると定義
されていない動作になります。観測的等価性と安全でないコードです。

Finally, there are outright bugs in the compiler.
最後に、コンパイラには明らかなバグがあります。
https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3A%22I-unsound+%F0%9F%92%A5%22
2020/12/28(月) 08:35:49.12ID:1wnarVmc
まあ大体その通りだわな。matkladはわかりやすい文章書くわ。
2020/12/28(月) 11:36:31.94ID:OYitjU6y
スマートポインタ絶対に使いたくない理由はよくわからんが
rustでも生ポインタ使えばよいのでは

コンパイル時間についてはcraneliftと差分コンパイルの進化に期待かな

その他の議論については影響は限定的だし
影響を受けない領域でrustを使えば良いのでは
議論の俎上には挙がっているし徐々に改善されていくでしょう
2020/12/28(月) 12:53:26.99ID:UcUcH/pf
>>510
>その他の議論については影響は限定的だし
ところがC/C++が担ってきた領域ではそれが大問題になることが多いので
RustはC/C++の代替には成りえない。

>議論の俎上には挙がっているし徐々に改善されていくでしょう
少子化も日本の経済衰退も非常に何十年間も議論の俎上に上がっている
のに改善されていく気配は全く無いことからも分かる様に、
そんなことは一般的には成り立たない。
2020/12/28(月) 12:58:19.94ID:UcUcH/pf
>>510
>rustでも生ポインタ使えばよいのでは
Rustのsafeモードでは生ポインタは使えないんだが。
2020/12/28(月) 13:13:50.09ID:N6A7dpOQ
>>512
実際に安全ではないので unsafe なのはあたりまえだが。
C++ のように常に危険なほうが良いなら C++ を使ってろよ。
2020/12/28(月) 13:15:56.66ID:UcUcH/pf
>>513
Rustはメモリーマネジメントの仕様がちゃんと公開されて無いので
C++よりずっと危険。
2020/12/28(月) 18:08:21.04ID:1npJXF9+
>実行速度が遅いがコンパイルが速い言語で書かれたプログラムは、
>実際には速く実行できるようになる。

最近この苦情よく聞くんだけどどんなもんなの
コンパイル時間のボトルネックなんて
考える時間に比べたらたいしたことなくない
何十分もかからんだろ
2020/12/28(月) 18:22:47.18ID:1wnarVmc
お前が弄る小さいプログラムではそうなんだろうね。
2020/12/28(月) 18:27:17.21ID:1npJXF9+
どんなん
2020/12/28(月) 18:58:25.81ID:9g/X/cXA
CIとかでめちゃくちゃ時間かかるのはRustの醍醐味
2020/12/28(月) 19:03:06.03ID:yEfXJ2Ei
>>515
今のRustコンパイラはコア数で良くスケールするので
開発用の32コアマシンなら快適だけど、古いノートPCだと辛い、みたいなことはあるな
Actixみたいに大量の依存関係を要求するやつ+しょぼいシングルコアなら数十分かかるかもね
2020/12/28(月) 19:27:10.85ID:yEfXJ2Ei
個人的にはクレート単体で遅いと思ったことはなくて、体感では数万行のコードでもgccより速いかな、という感じ
なので遅い要因はほぼ依存関係の多さだと思っている

C++とかだと特定のディストリビューションの特定のバージョンでコンパイルエラー、みたいな地獄のデバッグが待っているので、それを回避するコストとしては十分安いと思うけど
2020/12/28(月) 22:08:45.00ID:mQPXLAV2
今の方法だとまだ依存crateのコンパイル待ちになるのにスケールする?
>>518に尽きる
2020/12/28(月) 22:37:04.04ID:yEfXJ2Ei
>>521
もちろん完全に直列な依存関係はスケールしないよ
もしそういうクレートがあるなら分割すれば改善するかもしれないし
具体的に挙げて欲しい
2020/12/29(火) 01:19:43.87ID:k23+wtCh
>>520
>個人的にはクレート単体で遅いと思ったことはなくて、体感では数万行のコードでもgccより速いかな、という感じ
C言語のコンパイル意が遅くなるのは、Win32のヘッダファイルの巨大さが原因
であることが多い。
それが50MB位有ったりして、ヘッダファイルだけで数万行から数10万行くらいあったりする。
そのパースが遅い。
なので、VC++では precompiled header を使っている。
2020/12/29(火) 08:29:57.63ID:+jeJmMuS
cとc++じゃコンパイル速度は桁違いだけどな。
2020/12/29(火) 10:56:10.54ID:2ROJabla
ライブラリの依存関係を自動で解決するエコシステムがあると
依存関係が巨大になりがちっていうのは
Haskell や JavaScript でもよく聞くけどな。

まあ自分でそのライブラリ群を書く手間、
既存のものを使うにしても導入の仕方を調べる手間に比べたら
多少の時間はかかっても自動でやってくれるほうがマシではあるし、
度を越したときは個別に改善するしか仕方がないんだろう。
2020/12/29(火) 15:03:36.81ID:FJxczyqV
依存関係のコンパイルは初回しかやらないんだから多少遅くても気にはならない
CIの場合はtargetディレクトリキャッシュすれば良いし
rust-analyzerの起動時間がちょっと気になるくらい
2020/12/29(火) 23:35:14.28ID:1sbIl3YX
>>522
昔より増えたapiとimplを分離したクレートは

自分のプロジェクト->api->impl->implが依存するcrate(s)->...

と直列に依存してる。log,slog,serde,thiserror,webrender(etc.)
それに直列に依存するかどうかよりcargoもrustcのフロントエンドもまだ並列化対応が部分的でコンパイル単位の粒度が大きいのが並列ビルドの妨げになるでしょ。

>>526
CIはたしかにキャッシュが効けばいいけど、アナライザの話なら初回しかやらないことはないよ。
アナライザの場合は解析結果が無効になるたびに起きる。
intellij rustはプロジェクト開くたびにやってるし。
JDTみたいにon the fly analyzeするとソースコード変更するたびに解析するから依存グラフは使い回せても他は都度、解析する必要がある。
2020/12/30(水) 00:32:35.13ID:5c2z0B/k
>>527
言葉足らずですまん
(解析結果をメモリ上にしか持たない設計だから起動時に解析を全部やり直す)rust-analyzerの起動時間が気になるくらい(がコンパイル時間に関して気になる点)
と言いたかった
529デフォルトの名無しさん
垢版 |
2021/01/01(金) 09:10:16.97ID:WB+Ueidc
#![feature(min_const_generics)]だけじゃなく#![feature(const_generics)]も2021に入って欲しいな
2021/01/01(金) 12:06:39.72ID:y/yrEKhd
全く話は変わるけど、メモリ不足で Box::new に失敗したら、panicが起きて
プログラムがそこで停止するだけ?
2021/01/01(金) 12:08:13.77ID:y/yrEKhd
>>530
仮にそうだとすると、Cのmalloc()やC++のnew TYPEに比べるとエラー処理は
省ける反面、エラー処理を書きたくてもかけないね。
まあ、滅多に起きないので書いてもしょうがないけれども。
2021/01/01(金) 12:36:28.83ID:y/yrEKhd
*C++
TYPE *ptr = new TYPE; //メモリ不足の場合ptrにはNULLが返される。
*Java
TYPE obj = new TYPE; //メモリ不足の場合例外がthrowされる。
*Rust
Box<T> obj = Box<T>::new(T()); //メモリ不足の場合panicが生じアプリがダウンする。

Rustは、高度な安全性を要する分野や組み込みでは困るかも。
それに記述が長い。
2021/01/01(金) 12:40:33.89ID:mLxH8qq6
C++のnewはメモリ不足のとき通常は例外が送出されるぞ
メモリ不足でnullptrを返すにはnew(nothrow)にしないといけない
2021/01/01(金) 12:54:35.66ID:y/yrEKhd
>>533
昔、
TYPE *ptr;
if ( (ptr = new TYPE) == NULL ) {
 printf( "Memory allocation erro has occured.\n" );
}
みたいに書いていたことがあるけど、これは昔のC++でも間違っていたのだろうか?
2021/01/01(金) 12:57:46.63ID:y/yrEKhd
Javaは、例外をthrowする関数を呼び出した場合、必ずtryブロックで囲むか、
または、呼び出しもとの関数の宣言の最後にthrow/throws属性をつけるかしないと
いけないんだけど、なぜかnew演算子の場合だけはこの規則の例外で、
tryブロックで囲むこともthrow/throws属性を付ける必要も無いらしい。
ただし、tryブロックで囲んでcatch文でOutOfMemoryErrorという例外を
捉えることは出来るらしい。
意外と良く考えられていて、便利そう。
2021/01/01(金) 17:48:44.20ID:tSM4l1tY
検査例外等も知らない人が言語仕様にケチつけるなよ
2021/01/01(金) 18:19:22.53ID:y/yrEKhd
知識が無くてもそれが使いにくいことが分かる人もいれば、
知識があってもそれが使いにくいことが分からない人もいる。
その差はイマジネーションや経験や頭の良さの差。
2021/01/01(金) 19:06:09.23ID:tSM4l1tY
知識も経験もイマジネーションも頭の良さもない
お前さんどうすんの?
2021/01/01(金) 19:06:27.88ID:kK2SMYXF
20年以上前?のC++だとNULLが返ってきてたみたいだな
C++98の頃には例外が投げられてる
540デフォルトの名無しさん
垢版 |
2021/01/01(金) 19:07:24.81ID:Vr3i+dZB
出た、”地頭”信者w
2021/01/01(金) 19:20:38.81ID:roXbFcsK
Rustのpanicはスレッド単位ですよ
2021/01/01(金) 19:55:37.74ID:BepzsDBS
プラットフォームにもよるのでは
panic=abort
しかない環境もある
2021/01/01(金) 22:11:27.78ID:CysAMwpt
かなり初歩的な質問で申し訳ないんだけど、例えばHashMapをイテレータで舐めてるときに内部でそのHashMapを更新したいときはどうするのがベストなの?
例えば次のようなケースではどうすれば……

https://play.rust-lang.org/?version=stable&;mode=debug&edition=2018&gist=f6c554ab761450881f28e48faa55bf8c
use std::collections::HashMap;
fn main() {
let mut map: HashMap<_, _> = HashMap::new();
for i in -5..=5 {
map.insert(i, i);
}

for (key, value) in map.iter() {
if *value == 0 {
continue;
}
if let Some(another_value) = map.get_mut(&(-key)) {
// keyの絶対値が同じものを処理して、処理済みにする気持ち
*another_value = 0;
}
}
}
2021/01/02(土) 00:25:45.81ID:z4o0QpSV
>>543
map.iter() を map.iter().cloned().collect::<Vec<_>>() にする
2021/01/02(土) 00:53:14.75ID:aqs6ioY6
keyの絶対値が同じものでgroupingしてからイテレート
546デフォルトの名無しさん
垢版 |
2021/01/02(土) 02:08:00.06ID:S8wF2Q3x
rust的にはそういうことしないのがベストじゃない
俺だったらキーだけ取り出してループさせる
2021/01/02(土) 09:20:56.29ID:ZeOmz+/p
>>544-546
ありがとう!
しかしRust的には褒められたやり方じゃないんだね
LL言語脳から切り替えないといけないなあ
548デフォルトの名無しさん
垢版 |
2021/01/02(土) 14:15:48.62ID:RXFdEIXY
逆に-keyで絶対値にする言語とかあんの?
Rustではkey.abs()だぞ

> keyの絶対値が同じものでgroupingしてからイテレート
ソース見る限り元キーはそのままで{-1: 0, 1: 0}みたいにしたそうだからグルーピングでは絶対値にキー統一されるからダメだね
2021/01/02(土) 15:20:56.88ID:NIm/iweY
>>543
イテレータを回してるときに内部でそのcollectionをいじくる一般的な方法を聞きたかっただけで、そのコードはただ説明のためのモックなのでコードの妥当性とかはどうか気にしないでください……
550デフォルトの名無しさん
垢版 |
2021/01/02(土) 16:10:45.39ID:S8wF2Q3x
これは個人的な解釈だけど、ループ中にコレクションをイジるのを許可すると要素の追加削除も許可されるので、動作が想定しにくいから言語に関わらずやるべきじゃないと思う
2021/01/02(土) 17:40:37.90ID:QD9HT9ch
有名なアルゴリズムでも破壊的に処理を進める物は少なくないから
それらをリソースを押さえたままより安全に実装するかという問題はある
2021/01/02(土) 20:33:28.09ID:1irTnsdt
単純に破壊的操作とイテレータの組み合わせが良くないんだと思うけどね
基本的なアルゴリズムの実装でならC++でも大抵インデックスアクセスするし
2021/01/03(日) 01:40:10.34ID:qKjMqlyr
絶対値で比較されるようなkeyの型を用意してBtreeMapにぶちこんでiter_mut()すれば
絶対値が同じキー同士は連続して現れるからうまいことやればやりたいことはできるのでは
コード複雑になりそうだけど
554デフォルトの名無しさん
垢版 |
2021/01/03(日) 02:42:58.53ID:ez188GTZ
>>550
C++狂い「安全性よりも論理的、数学的に正しいかが重要」
555デフォルトの名無しさん
垢版 |
2021/01/03(日) 15:16:13.09ID:vPi839cG
Rustで大量の敵が同時に出現する2Dゲームを作ろうと考えています。
Amethyst、ggez、Bevyの中で最もおすすめのゲームエンジンはどれでしょうか?
2021/01/03(日) 15:58:43.30ID:NLnLDzaH
イニダン亡き後の移住先か…!
2021/01/03(日) 17:51:55.22ID:CkWAgifP
スライムが5000匹現れた!
2021/01/03(日) 20:23:57.03ID:ixJIhJjK
>>552
まあ通常そういう場合はint値でモロにインデックスアクセスするわな。
これがrustとは全く馴染まない。
2021/01/03(日) 21:45:20.19ID:hFPMmBD/
single writer or multiple readerのモデルに沿うようなロジックに変換するか
interior mutabilityを使うかのどちらか
2021/01/05(火) 22:41:10.79ID:fwCCjwkT
>>555
個人的にはAmethyst。
なぜなら俺が個人的にECSアーキテクチャが大好きだから。
小さなプロジェクトに向かないとか言われるけど知らないそんなの。
2021/01/05(火) 23:32:43.62ID:rno8zcnm
RustでTDみたいなブラウザゲー作った猛者おりゅ?
562デフォルトの名無しさん
垢版 |
2021/01/08(金) 08:35:58.68ID:WNrzsb9T
なんでこんなゴミを100M単位でボコボコダウンロードせなならんのや

ゴミ
2021/01/09(土) 00:36:27.01ID:ntvhJtwv
>>562
それって回線がゴミなだけじゃ...
2021/01/10(日) 12:11:15.45ID:smlN1G6e
評価順序のルールがよくわからないんですが、
タプル生成のときの呼出し順序って保証がありますか?
つまり

(foo(), bar())

みたいに書いたときに foo が常に先に呼ばれることは保証されますか?
2021/01/10(日) 13:02:46.89ID:fqhi9u3I
保証されてるんじゃない?
でも呼び出し順が重要なら行を分けて書いてからtupleに入れたほうがいいような気もする

The meaning of each kind of expression dictates several things:
・Whether or not to evaluate the sub-expressions when evaluating the expression
・The order in which to evaluate the sub-expressions
・How to combine the sub-expressions' values to obtain the value of the expression
https://doc.rust-lang.org/reference/expressions.html
2021/01/10(日) 15:22:53.59ID:fqhi9u3I
評価順序についてはもう少しわかりやすくリファレンスを更新する予定みたい
https://github.com/rust-lang/reference/blob/964dc5bab5f7418aea36233c271ceedaea216598/src/expressions.md#evaluation-order-of-operands
https://github.com/rust-lang/reference/pull/888/
2021/01/10(日) 15:34:43.17ID:smlN1G6e
>>565-566
ありがとうございます。
無学なので少し書き方が分かりやすくなっても英語だとしんどい……。
2021/01/11(月) 14:09:54.51ID:MiJ5pxpq
ファイル (またはネットワーク) から得られる所定の書式のレコードの繰り返しを
イテレータとして抽象化したいと考えました。
(ちなみにレコードの繰り返しの前にレコードの個数を含むヘッダもあります。)

しかし IO はエラーの可能性があります。
書式の仕様に違反する入力になっている可能性もあります。

イテレータが返す型を Option<Result<要素の型,エラーの型>> としてしまうと
エラーの時点で終端という扱いにならないので様々なメソッドと組み合わせ難いですし、
Result を挟まないとエラーの内容を返せないのでハンドリングしづらいです。

何か綺麗にやれるイディオムのようなものがあったりしませんか?
2021/01/11(月) 15:21:23.54ID:8i1ZTkbL
エラーの時点で終端にするかどうかは呼び出し側が決めることじゃない?
Option<Result<T, E>>もResult<Option<T>, E>もイディオムとしてよく使われてる
2021/01/11(月) 15:47:03.74ID:MiJ5pxpq
>>569
出来るか出来ないかで言えば出来るし好きにすれば良い話ではあるんですが、
標準で良いされている様々なメソッド (たとえば map のような基本的なメソッドさえ!)
と「組み合わせ難い」ということが綺麗じゃないなぁという気持ちなんですが、
そこらへんの不格好さは許容するしかない雰囲気ということでしょうか?

(通常の終端に到達するのとは別に) 中断を表現する方法があって
中断の理由を伝播するのに便利な語彙を詰め込んだクレートがあったりすると
助かるんですが。
2021/01/11(月) 16:05:22.66ID:cgTcg0uf
>>570
公式にあるイディオムっぽいのはこれとか。
https://doc.rust-lang.org/rust-by-example/error/iter_result.html

クレートは探すと色々見つかるけど、結局「便利な」ってのが人それぞれだし、あまり流行ってる感じはしないな。
むしろその中断表現をうまくやるアイデアがあるなら自分で作ったほうがいいのでは。
2021/01/11(月) 16:41:17.67ID:8i1ZTkbL
>>570
組み合わせ難いと言ってる内容をコードで示してくれないとなんとも
573デフォルトの名無しさん
垢版 |
2021/01/11(月) 20:34:05.33ID:D6pgjuRM
イテレータとして抽象化したいってどういう意味なの
Iteratorをimplするってことなのかしら
2021/01/11(月) 23:06:51.09ID:MiJ5pxpq
>>573
ここでいう「イテレータとして」というのは std::iter::Iterator に限るわけではなく、
繰り返しを表現する何らかの型定義と思ってください。
適当なクレートがあるならそれでいいですし、考え方だけでもいいです。

欲しい機能をあらためてまとめると

・ 繰り返しに (終端に到達する以外の) 中断の方法が用意されている
・ 中断したときに中断の理由 (エラー型の値) を伝える方法がある

なのですが、
std::iter::Iterator だと next が返す Option<Result<T, E>> でエラーのときに
「中断」しようとすると for 文の中で break する書き方くらいしか思いつかず、
自分で便利なものを作ろうにもどう作れば便利になるのかも
想像がつかないのです。
2021/01/12(火) 02:11:34.65ID:yVKQhIbd
>>574
https://play.rust-lang.org/?version=stable&;mode=debug&edition=2018&gist=aaf882f54a7b6330ee6ad2106be92717
こんな感じでscan使えばNoneを返したところで
イテレーションを中断できるしErrの値も列挙できる
2021/01/12(火) 02:12:25.76ID:yVKQhIbd
中断するだけなら take_while 使うという手もある
577デフォルトの名無しさん
垢版 |
2021/01/12(火) 08:20:11.60ID:tB/XA0DN
俺もtake_whileを思い浮かべたけど関数を作るわけじゃないんでしょ
ゴールがいまいちみえないからイメージでいいのでコードで用件を示してほしい
2021/01/12(火) 11:44:28.63ID:d2vxqIR1
単にエラー返して中断したいだけならResultにcollectしたりtry_for_eachで消費すればいいよ
イテレータアダプターとしてエラーも含めて列挙しつつ次につなげたいなら>>575が書いてるscanやtake_while系
https://play.rust-lang.org/?version=stable&;mode=debug&edition=2018&gist=113dcf689b4d941c89e714ebb1414958
579デフォルトの名無しさん
垢版 |
2021/01/12(火) 20:39:12.01ID:jo+wjg9+
AsRefトレイト使ってenumから&str返すのっておかしい?
Display実装で文字返してたらアロケートされるからAsRef使おうと思ってるんだけど
2021/01/12(火) 20:51:33.48ID:yLoNqPBg
Rustの利用状況調査、ビジネス利用が進む一方で習得の難しさなどが依然課題
https://www.atmarkit.co.jp/ait/articles/2101/12/news046.html
2021/01/12(火) 21:41:00.77ID:yVKQhIbd
>>579
AsRef に拘らず独立した as_str 用意した方が良いと思う
582デフォルトの名無しさん
垢版 |
2021/01/12(火) 22:42:54.02ID:jo+wjg9+
AsPath が AsRef<Path> になった過去もあるから汎用性持たしてas_str実装するよりAsRefで実装する方がいいといいと思うけど他の人はどう思う?
2021/01/12(火) 23:59:44.33ID:d2vxqIR1
as_strに一票
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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