Rust part8
■ このスレッドは過去ログ倉庫に格納されています
>>6 ありがとうございます。 上手くいきました。 ミスがある前提で作られたソフトウェアなんぞ使いたくないわ。 個人のミスが重大な問題にならないようシステムで防ぐんだぞ 1つのミスがそのままProductionのバグになるわけじゃないから 個々の部品が予期しない故障をする前提で設計したシステムと 個々の部品は想定外の故障はしない前提で設計したシステムと どちらのほうが高い信頼性を実現できるのかは歴史を見れば明らか だから優れたプログラマーは自分がミスを犯す前提で そのミスが重大な問題につながらないよう個人単位でもシステムを構築してる >>10 おまえの関わった製品には署名しといて。 絶対使わないから。 >>11 5chに書き込んでる時点で 何か人生ミスってる気がする https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=511e2be2ae90342a9c36f759e73108b6 勉強がてらたらい回し関数をメモ化仕様で書いてみたんですけどあってますかね…自信がないです プルリクとかも出す前にさんざん確認してんのに出してからすぐ「あ、ここ間違ってた…」みたいになるよね(´・ω・`) Vec<String> を拡張すると定義外ってエラー出るんですけどなんでかわかる人います? 他のライブラリでVec拡張してるソース見ると特殊なことせずにimplできてるんですけどどうすればこのエラー取り除けますか? impl From<Vec<&str>> for Vec<String> { fn from(v: Vec<&str>) -> Self { v.into_iter().map(String::from).collect() } } error[E0117]: only traits defined in the current crate can be implemented for arbitrary types | 88 | impl From<Vec<&str>> for Vec<String> { | ^^^^^---------------^^^^^----------- | | | | | | | `std::vec::Vec` is not defined in the current crate | | `std::vec::Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | >>18 ざっくりいうと 外部crateで定義された型 + 外部crateで定義されたtrait の組み合わせでインプリするのは無理 どっちか片方が自crateで定義されたものなら問題ない coherence ruleとかorphan ruleとかいうやつ https://doc.rust-lang.org/error-index.html#E0117 >>19 おお、ありがとう impl Vec<&str> の単体でも駄目だったから自trait作って実装した! 結構制約厳しいな 外部トレイトに実装するならめんどくさいけどマーカーつけとけよって意味かな こんな関数は書けますか? @ イテレータを受け取る A 受け取る引数は @ のただひとつのみ B 条件を満たす範囲を「スライスで」返す スライスを作る記法は &s[1..10] みたいな感じなのでスライスの元になるオブジェクト s が必要なように見えますが、 スライスを返したいというのはいかにもありそうなことなので出来ないはずはないだろうという思いもあります。 イテレータは実際にはなんらかのシーケンスをたどるものではなく値の生成器である場合もありますが、 それらを区別するような制約を表現できますか? >>21 無理じゃね? スライスじゃなくtakeやskip使ってイテレータを返すべきケースだと思うけど スライスは連続したメモリ領域である必要があって 任意のイテレータがその条件を満たすのは不可能。 たまたま連続した場合だけスライスを返すのはunsafe使えば書ける。 ただ普通はイテレータ返してランダムアクセス必要なタイミングでcollectすると思う。 あと標準のイテレータは特に値の生成方法に関する型制約はないので 区別したいなら独自のイテレータ型を作って 標準イテレータへの変換を実装する感じかな。 入力が連続したメモリ領域だってんなら引数をイテレータじゃなくてスライスにすればいい 当たり前だけどスライスを作れるもの以外からはスライスは作れないからな >>23 >たまたま連続した場合だけスライスを返すのはunsafe使えば書ける。 イテレータを受け取ってスライスを返すとした場合 スライスの元になってるシーケンスのlifetimeが関数内に閉じるから unsafe使ったとしてもborrow checkerにひっかからない? >>27 from_raw_partsでスライスを作った場合は元のポインタ由来のライフタイムは関係なくなるので ボローチェッカは通るんじゃないかな? もちろんそのスライスの実体が生きているかどうかは 自己責任になるけど。 >>28 なるほど イテレータからイテレータの元のシーケンスが取得できればそれでいけるってことか ちょっと見てみたらslice::Iterのas_sliceとかも内部でfrom_raw_parts使ってた 自分では使わないと思うけど勉強になった >>22-29 ありがとうございます。 スライスの役目や Rust の習慣について誤解していたみたいです。 【誤解】 スライスは範囲を表現する高級なオブジェクト Vec にも配列にも使えるのでコンテナ全般に使えると思った 【正解】 スライスは「メモリの」範囲を表現するオブジェクト 実体としてはいわゆる fat pointer 【背景】 Vec は内部的に連続したメモリ領域で管理しているので普通の配列のようにスライスを作れる C++ でいえば vector の data や string の c_str みたいなもの 【見落とし】 配列でも Vec でもスライスの型表記は同じなのでどうしてだろうと気にかかってはいたが掘り下げて調べなかった 型が同じなのは実際に同じだからなわけですね 質問あると自分の理解が怪しいのが分かって助かるわ。 let template = if spaces { "{1}{0}{1}" } else { "{1}{0}" }; format!(template, 1, 2); これだとリテラルかけってエラー出るだけど、解決方法ないかな? iter[1..4]とか書けた方がiter.skil(1).take(4).collect()よりシンプルでええやん! とは思ったが、そういう使い方したらそもそも駄目よ、という意思が表れているのかもしれん >>33 標準のformatでは無理だね。templateのパースエラーを返す手段がないので。 dynfmtクレートとかならいけると思う。 >>34 range(&self, from: usize, to: usize) -> Option があればいいのにね >> 35 ありがとう、リテラルのみは統一感出るけどかなり不便だね。 デバッグ用じゃなくともDisplayとかもあるからResult返すマクロも入れといてくれたらいいのにね >>34 Rust的にはcollectによるメモリコピーみたいな 重い操作は見た目上も重くしたいんだと思ってる。 collectを二度書くと罪悪感で一度にならないか一生懸命考える >>33 単純な用途ならリテラル返すマクロを書くといいかも 複雑な用途ならテンプレートエンジンかな macro_rules! my_format { (true) => ("{1}{0}{1}"); (false) => ("{1}{0}"); } println!(my_format!(true), 1, 2); >>41 CodeLLDB初めて使ってみたがオレ環では特に問題なく使える ソースマップ定義してないから標準ライブラリとかにstep inすればバイナリで表示されるけど 自分のソースのブレークポイントでバイナリ表示はされない 単純にdebug symbolが有効になってないとか? launch.jsonのcargoのコマンド確認してそれでbuildしたバイナリを rust-lldbでデバッグできるかどうかで切り分けてみたら? 解決しました 上記はMac用のデバッグのやり方のようです vscodeでrust始めたんだけどオートコンプリートがまともに働いてくれてない気がする メソッド内の変数だと候補を出したり出さなかったりする >>45 vscodeやめてインテリなんとか使えば? vscode での Rust の補完って LSP を使うんでないの? 処理系と連携するって最強じゃんと思ってたんだが。 コンパイラから出てくる補完情報が成熟してないんで、まだ完璧には遠い 独自の解析はracerとintellij rustがやってて、精度はintellijの方が高い あんまIDE使いたくないからrlsには頑張って欲しい 本体のソース見たいけど/* compiler built-in */ってなってて読めない。 どうやったら見れる? Rust の char::is_ascii とかは pub const fn is_ascii(&self) -> bool なのに is_whitespace とかは pub fn is_whitespace(self) -> bool みたいになってるのなんでだろ? &self でも self でもどっちかに統一してよさそうな気がするんだけど。 なんかツイッターで以下2つについてコンパイルできねーっていうつぶやきがあったんですが、 試してみたらコンパイルできちゃったんですがどういうことなのでしょう Rust2015/2018どっちでもコンパイルできちゃいました //その1 let y: &i32; let x = 5; y = &x; println!("{}", y); 参照元yの変数宣言が参照先のxより先に変数宣言されたからエラー。 //その2 let mut x = 5; let y = &mut x; *y += 1; println!("{}", x); //これがエラー >>50 is_asciiはstrやsliceにもあるからそれに揃えたんじゃないかな >>51 NLLで救えるようになったケースだね。 Rust1.30くらいまで戻せばエラーになるけど 今は2015でも2018でもNLLがデフォルトなのでエラーにはならない。 >>52 なるほど、全部を &self に揃えなかったのは、やっぱ self の方が効率的って判断なのかな? ワイはまだ初心者で Rust 脳になりきれてないんだけど、参照渡しってのは実質的に (C/C++ で言うところの) ポインタをやりとりしてる感じでしょ? (単純な場合は最適化で消えると思うけど。) char 程度の大きさならポインタを渡すのでもコピーして渡すのでも差はないし、ポインタだと間接参照になる分だけ無駄っぽい。 という理解をしてて、 char のメソッドは全部 self でいいくらいじゃないかと思ってた。 >>55 ascii系は昔はAsciiExtってトレイトに別れてたから その名残だと思う。 >>56 歴史的経緯ってやつか。 比較的新しい言語なのに、やっぱりそういうこともあるのね。 The Rust Programming Language 第2版で勉強中なんだけど この内容に連動した練習問題か使用例みたいなのどこかにないだろうか?英語でいい https://www.rust-lang.org/learn このページの上のほうにある3つのボタンがそれそれ 1. The Bookの最新版 2. Rustlings course(練習問題的なやつ) 3. Rust by Example(使用例) 英語で問題ないなら2018対応してる最新のThe Book読んだほうがいいかも 英語がしんどい人 (日本語しかわからん人) にオススメなのはありますか? >>59 ありがと こんな感じの欲しかった って言うかPDFだけ読んでたから思い付かなかったけど本家にあったのか 手を動かしたいなら自転車本もあり オライリーはちょっと古くなってるからなー オライリー本の古くなってる箇所はEdition Guide読めば問題ないよ 多少古くてもOwnershipやLifetimeあたりの重要コンセプトをわかりやすく書いてるものがおすすめ >>58 みたいに英語でいいならrustupでインストールしたら付いてくるdocとそのリンク先にあるやつ読んだほうが良いぞ。 // ランタイム持ってないからasync/awaitがゼロコスト理論斬新すぎる 自クレートの名前やバージョンを取得するマクロって無かったっけ? Rust のライブラリって検索できるようになってるじゃん? あれって名前だけじゃなくて引数の型とかで検索できたりしないのかなぁ。 Haskell (GHC) の Hoogle みたいに >>67 あ、 Inparameters ってやつをクリックすれば出てくるのか。 >>69 へー。 そのための専用のマクロってわけじゃなくて cargo が環境変数を設定してくれるって話なのね。 Cargo.toml を見ないとわかるはずもないからなんらかの連携があるのは当たり前といえば当たり前だけど。 io::Errorとかってprintln!("{:?}", err )とかしても Os { code: 13, kind: PermissionDenied, message: "Permission denied" } みたいに出るだけで「どのファイル」かが分からないんですが、外部のクレートの関数から上のようなエラーが帰ってきた場合それが「どのファイル」によって起きてるのかというのはどうやって知れば良いんでしょうか? >>72 自分が明示的にパスを渡してるケースじゃなければ クレートの作者にファイルパスも入れてクレメンスするしかないかも バイナリサイズはまだCの方が全然小さいけどRustはC以上になにが含まれてるの? もちろん標準ライブラリとかは使ってないやつはバイナリに含まれないよね? >>74 明らかに大きいのはbacktrace用のデバッグシンボル。 これはstripすれば縮む。 それ以外はC側が共有ライブラリとしてどれだけ外に出してるかによるかと。 メモリ管理がランタイムにあるしdrop checkerもあるからランタイムはデカイよ。 >>75 backtrace用のデバッグシンボルってreleaseでもついてくるの? >>76 drop checkerってborrow checkerの書き間違え?borrow checkerってcompile-time以外でも走るのって一部の実装だけって認識だけど ARCとか使うとランタイムとか増えるの分かるけど使ってないハロワだけのやつでもCより多いのが疑問 Windows10のキャラクターがゴミ過ぎて無駄に苦労する やっぱLinux使うしか無いんか? でもゲームしたいからWindows環境が良いんだよな… >>77 releaseでもデバッグシンボルはついてくる。 取って欲しいってIssueは立ってるけど stripすればいいって感じなのか、あまり動きはない。 あとCのHelloWorldが小さいのはコードの大半が libcにあるせいなのでは。 組み込みで使おうなんて本気で考えてる奴はこんなところで聞いたりせんだろ。 cargo install mdbook としたとき、依存するライブラリクレートも一斉にインストール (というかキャッシュみたいな扱い?) されたようです。 ローカルに入ったライブラリクレートのドキュメントから一斉に、網羅的に検索する仕組みはありますか? 標準ライブラリのドキュメントは名前や引数で検索できますが、それを手元に入っているライブラリ全てに拡大したようなものが欲しいです。 >>84 ビルド用の一時ディレクトリ以下に展開されただけで他から使えるようにはなってないよ >>85 そうなんですか。 Windows でやってるんですけど、 C:\Users\<ユーザー名>\.cargo\registry\src に入っているのはビルド時の一時ファイル扱いという理解でいいんですかね? 他のプログラムをビルドしたときに必要になるライブラリクレートに共通するものが (このフォルダに) あったときでも 使いまわしはされないんでしょうか? 見かけ上は独立してるけど cargo が裏でうまいことやってくれるって感じなんでしょうか? 本当は Cargo book を読めばいいんでしょうけど、英語がわからなすぎて基本的な理念がよくわかってないです。 $ cargo doc --open doc生成すればプロジェクトの依存クレートすべてWeb形式で検索できるけど そういうことではない? >>84 cargo installはバイナリクレートをインストールするためのワンライナーなんで ライブラリクレートをどうこうする為のものではないよ。 バイナリのビルドに成功したら.cargo\binにコピーしてゴミは削除する。 バイナリクレートのドキュメントを読みたいならそれ自身を読みに行くんだよ。 rustdocは開発者向けでユーザー向けじゃない。 mdbookのrustdocが読みたいなら単にソースコードをクローンして自分でcargo doc叩けばビルドしてくれるけど。 構造体のメソッドでメンバ変数の値ひっぺがすのにstd::mem::take使うの面倒だな >>87 「そのプロジェクト (に依存する全ての)」ではなく「ローカルに残っている全ての」というつもりでした。 >>88 > cargo installはバイナリクレートをインストールするためのワンライナーなんで > ライブラリクレートをどうこうする為のものではないよ。 「為のものではない」ということは察していたんですが、 ライブラリのソースコードは残っているので裏で Cargo が動くために情報を残してもいるのだろう と考えて特定のプロジェクトに限定せず横断的な処理をする方法があるのかどうかということを考えていました。 バイナリクレートをアップデートするときのために残してあるだけなんですかね……? とりあえず、プロジェクトごとに独立していると考えておきます。 >>90 .cargoは全プロジェクト共通のキャッシュなので プロジェクトまたいでも再利用はされる。 ただcargoコマンド自体はプロジェクト毎の操作しか提供しない、という感じ。 そういうツールを作ること自体は可能と思うけど。 >>91 なるほど。 見かけ上はプロジェクトの独立性があるように抽象化されているという感じですね。 なるべくなら過去に使ったことのあるライブラリクレートから使えそうなものを 探した方がキャッシュ (?) の増大を抑えられるし、 よく使われるライブラリの方が信頼性が高いだろうというのが元々の動機でした。 ツールの使い方もおぼつかないので定番と言えるのがどのあたりなのかとかいった肌感覚もなくて、 実際のコードを色々と見て回るのにどういうやり方が良いのか模索しています。 https://ideone.com/6mGYO9 これの14行目15行目のところを10行目のところのように1つの文で書ける方法ってありますか? Haskell の default 宣言みたいなのは Rust にありますか? たとえば関数 foo が返す値の型が a もしくは b の可能性があり、 関数 bar が受け取る値の型が a もしくは b のときに bar(foo()) という式で型が定まりません。 このときに a と b の間での優先度を決める方法があるかという質問です。 具体的な状況があるわけではなくて、言語機能を学ぶ中で生じた疑問です。 >>93 こんな感じかな。 buf = buf.replace(ch, &<String as std::iter::FromIterator<&char>>::from_iter(&[' ', ch, ' '])); 俺だったらformat!(" {} ", ch)にするかforを[" ( ", " ) ", ...]で回すかな >>94 >たとえば関数 foo が返す値の型が a もしくは b の可能性があり Rustで戻り値の型が1つに決まらない関数書ける? 型が曖昧な時はだいたいターボフィッシュでなんとかなるやろ >>94 型が定まらない関数は定義不能。 aまたはbを返したいならenum c {a, b}にしてcで返すしかないかと。 >>94 rustはsum typeしかない。それだと実行時に型を評価する方法とunion typeがいる。 正直TypeScriptの1 | 2 の型記法欲しい >>94 って多分こういう事では? trait X { ... } impl a for X { ... } impl b for X { ... } fn foo<T: X>() -> T { ... } fn bar<T: X>(_: T) { ... } bar(foo()) Rust の文法詳しくないんで間違ってたらすまん >>103 もしそうならdyn Xで返せばいいね。 その場合は型がAかBかの評価は実行時になるけど どちらにしてもAとBのどっちを優先する、みたいなのはないな。 >>103-104 近いですが a と b との関係がもっと無関係なもの (仮想関数を使えない) を考えていました。 コードにするならこんな感じです。 struct Foo {} struct Bar {} trait X<T> { fn foo(&self) -> T; } trait Y<T> { fn bar(&self, T); } impl X<Foo> for Foo { fn foo(&self) -> Foo {Foo{}} } impl X<Bar> for Foo { fn foo(&self) -> Bar {Bar{}} } impl Y<Foo> for Bar { fn bar(&self, _x: Foo){} } impl Y<Bar> for Bar { fn bar(&self, _x: Bar){} } fn main() { Bar{}.bar(Foo{}.foo()); } いずれにせよ方法はなさそうですね。 型を明記すればよい話ではあるのですが、ふと疑問に思ってしまったもので。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.4 2024/05/19 Walang Kapalit ★ | Donguri System Team 5ちゃんねる