Rust part8
■ このスレッドは過去ログ倉庫に格納されています
"処理と戻り値"を伴う""正常""の早期returnをしたいといってるだろがErrでラップして返すとかバカか? こういうSomeから取り出すだけの部分が冗長だから消えてなくなれつってんだよ is_none()でやるのは構文保証ではなく"プログラマーの注意力"による保証だからクソだつってんだよ let v = match foo.get() { Some(v) => v, None => { bar.modify(); baz.modify(); return Ok(bar, baz); }}; let v = if let Some(v) = foo.get() { v } else { bar.modify(); baz.modify(); return Ok(bar, baz); }}; >>347 だからその冗長な部分はマクロで潰せと言ってるんだが。 マクロが嫌なら無理としか言いようがないが。 宣言的な書き方の基本が分かってないんやろな Rust以前のレベル >>347 >"処理と戻り値"を伴う""正常""の早期returnをしたいといってるだろがErrでラップして返すとかバカか? えっ、 Errでラップして返してる? まぁそれはいいとしてearly returnだけじゃなく 戻り値の型と取り出した値をどうするかをセットで考えてないから そうなっちゃうんだと思うよ RFCざっと見てきたけど、あっちでも 「map_errでいいんじゃ?」「return;できねーよ」ってやってるな。 そんなに難解なリクエストでもないと思うんだが。 fn check<T>(mut f: impl FnMut(T) -> bool) と fn check<T, F>(mut f: F) where F: FnMut(T) -> bool って同意義ですか? >>354 恐らくだけど、前者は必ずその関数を定義する。 後者は、Fがその型の場合にのみその関数を定義する。 なお、このような場合の whereは、日本人感覚からすれば、ifと読み替えてもいい。 前者の場合 check::<T, F>() でコールできるが後者はできない これ https://docs.rs/try_or/0.2.0/try_or/macro.try_opt_or_else.html Unwraps an Option. If the result is None, calls the function $or_fn and returns its result. そもそもcheck::<T, F>()じゃ引数渡してないから呼び出せなくない? 試してないけど 構文で解決すべきところを皆が俺俺マクロで解決して統一感ない状態を生むのが良いと考えるやついるのか? if foo.is_none() { シンプルにこれでいいと思うんだが... これぐらいの細かい挙動で構文拡張しろとかマクロ書けとかなったらC++みたいになっていくのが目に見えるしから嫌だわ しかもこんな嫌だ嫌だ言ってて質問する立場なのにこんな逆ギレもしてて救いようがない 現状は335が冗長と言う状態で統一されてるんだからいいんじゃないの。 その冗長さをどうしても許容できない人は(少数派である以上)マクロで解決するしかないし、もし大多数が賛同できる新構文を思い付いたならRFC出せばいい。 test bench_test ... bench: 111,111 ns/iter (+/- 11,111) ベンチマークの +/- ってどういう意味? >>363 is_none()は==NULLや==nilと同じ書き忘れのリスクを伴う"プログラマの注意力"を消耗するだけのゴミだろ if letやmatchにしないとSomeだったときの処理書けないしょ rust実用化に成功したプロジェクトって何があるの?お前らの会社では成功してるの? rustで作ったメカの中でセックスしましたみたいな use chrono::{Utc, TimeZone}; assert_eq!(Utc.ymd(2015, 5, 15).to_string(), "2015-05-15UTC"); なんでこれって静的メソッドじゃないのにself省略で使えるんですか? https://docs.rs/chrono/0.4.11/chrono/offset/trait.TimeZone.html#method.ymd Utcはフィールドを持たないstructだから イメージ的にはUtc{}.ymdとしているかんじ 公開されていないLoopStateっていうenum使いたいんですけどコンパイラーオプションとか属性とかで使う方法ありませんか? https://doc.rust-lang.org/src/core/iter/mod.rs.html#371-422 pub が付いてないものをそんなに簡単に使えたらモジュールの意味がないやろ……。 そのモジュールをコピペして新しいモジュールを作れば自由に出来るんとちゃう? Docs.rsのメソッドの引数の見方がわからん 具体的には https://docs.rs/image/0.23.2/image/struct.Frames.html の pub fn new(iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a>) -> Self iteratorを受け取ってSelfを返す。 iteratorは各要素がImageResult<Frame>のもの Box<dyn …>してるのはコンパイル時にTrait ObjecのSizeが決まるようにするため (Generics使えば不要) ‘aはiteratorのlifetimeをSelfのlifetimeにするため >>380 解説ありがとう 上二行は理解できたんだが他がイマイチ・・・ >>381 dyn は C++ で言う抽象クラスみたいなもんだよ。 トレイトオブジェクトというのは実際にはそのトレイトを実装している様々な型の可能性があって、 それら全てを格納可能な大きさはわからない。 Box は C/C++ でいうポインタみたいな用途で使われる。 大きさがわからなくてもオブジェクトの場所を指すことは出来る。 「そのトレイトを実装している型ならなんでも」と「そのトレイトを実装している型のいずれか」というのは違う意味で、 ジェネリクスは後者。 言い換えると、実行時にディスパッチされる多相とコンパイル時にディスパッチされる多相ってこと。 コンパイル時に型がわかるのなら大きさもコンパイル時にわかる。 大きさがわかるなら Box を経由しなくていい。 ライフタイムの 'a は Frames の型引数の 'a と同じだから、 new の返り値 (Self) の寿命は iterator の寿命と同じになる。 Boxと&dynの違いって参照元がヒープかスタックかの違い? >>381 大前提として変数や関数の引数や戻り値はコンパイル時にサイズが決まってないといけない Iterator Traitを実装してる型を引数として受け取りたいからといって `pub fn new(iterator: Iterator<…>) -> Self` と書くと Iterator Traitのサイズがコンパイル時にはわからないのでコンパイルエラーになる `let foo: str;`でエラーになるのと同じ Box<dyn Trait>か&dyn Traitの形にすれば Iterator Traitへの参照(=Trait Objectというfatポインタ)になって 受け渡しするサイズが固定されるのでエラーにならない ジェネリクスを使って `pub fn new<T: Iterator<…>>(iterator: T) -> Self` と書いた場合は 実際の呼び出しに使われているTの型ごとにコンパイラがバイナリを生成するので コンパイル時にTのサイズが決まってる (impl Trait使った場合も同じ) >>382 も書いてるように前者は動的ディスパッチ、後者は静的ディスパッチなので 異なる型が混在するコレクションを使いたい時やバイナリサイズを小さくしたい時以外は ジェネリクスを選ぶほうが一般的 あーなんとなくわかってっきた ジェネリクスと同じことがトレイトオブジェクトでも実現できて、その書き方がBox<dyn...>ということか そもそもRustはかなり型のサイズに厳しいけどなんで? コンパイラの最適化のため? >>388 他言語なら暗黙的に参照として扱われるようなものも 明示的に&を付けたりBox化することを求めるから厳しく感じるんだと思う 明示的に求めるのはowned/shared/mutableの3つを 一貫性を持って区別して書くようにっていう設計選択じゃないかな >大前提として変数や関数の引数や戻り値はコンパイル時にサイズが決まってないといけない ↑これ他言語でも常識かもしれないけど自分はRustやるまで意識したことなかったよ > pub fn new(iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a>) -> Self 入力にimpl Traitってまだ無理なんだっけ? >>386 同じではない。 ジェネリックスはパラメトリック多相の事だから静的ディスパッチになるけどtrait objectは動的ディスパッチそのもの。 >>388 そう。 リージョンでメモリ管理するときリージョンのサイズが事前に決まるなら リージョンはヒープじゃなくてスタックに確保できるからrustは型システムが サイズが事前に決まる事を強制してる。 rustでは 途中で送ってしもた。 rustでは当たり前に見えるけどこんな事してるのrustくらいでヒープが必要ならクロージャさえも自分でbox化する必要がある。 スタック上に長さ不定のデータが作れるとバグの温床になる。 他の言語だと大体の値がヒープに乗せること前提で動いているんで気にしたことが無いのだと思われる。 C/C++でも非推奨なんだけど、初心者向け釣りサイトでは平気でやってることがあるし、できちゃうから面倒 配列サイズが決められてないかつ、関数内で配列生成するけど返り値はサイズ固定のスライス記法の書き方するようにする方法ってない? つまりはVecのアロケートが嫌な場合 fn name(v: Vec<A>) -> Vec<A> { v.iter().map(***).collect } これだとスタック確保できるけど無駄なデータ入ってるし、動的なサイズの配列を返せない fn name(v: Vec<A>) -> [i32; 10] { let mut arr = [0; 10]; for (i, x) in v { arr[i] = x} arr } こういうスライスのスタック版みたいな感じのことがしたい fn name(v: Vec<A>) -> [A] { let mut arr = [0; v.len()]; for (i, x) in v { arr[i] = x} arr } >>390 impl Traitは引数にも使えるよ >>393 [A]だとサイズがコンパイル時に決まらないから&[A]か&mut [A]を返すのはできる ただ入力がVecで長さが不定なので 出力の参照元にその長さの配列を使うのは無理じゃないかな あと関数内部で配列生成したら そのlifetimeが関数内に閉じるので参照も返せないね やるとしたら 外側のスコープで固定サイズの配列をバッファとして作っておいて 関数ではバッファを満たして返すイメージ C言語でいうところの if ( (c=foo()) == bar) { ...(cを使う処理) みたいなことやりたいんですがどうすればいいですか? fooが結構重くて2回呼び出したくないのですが、 let c = foo(); if c == bar {... とやるしかない? matchとifガード使えば似たようなことは出来る >>396 何かしらのライブラリでなんかないかな? static使うぐらいなら素直にVec使うわ... >>397 @ bindingってのを使う https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=b2a16356c2c790985ddd937ccc2ca826 >>398 match foo() { c if c == bar => { .. }, _ => (), } こういう感じでしょうか。この場合だと記載量としてはかなり微妙ですが何かに使えそうなので覚えときます。 ありがとうございます。 >>399 今回の場合はfoo()がboolじゃないのと、barが変数なのでシャドーイングされてうまくいかないようです・・・。 if let foo @ bar = foo() { ... みたいなことやろうとしましたがダメでした。 https://play.rust-lang.org/?version=nightly& ;mode=debug&edition=2018&gist=d580f91c98f26cf52a23791489914ec3 >>390 うーん難しいな プログラムの動作としては同じになるんじゃないのか Vecとかのコンテナ系の使い方は大分変わるよ 例えばイベント駆動の何かを作るときには考えた方が良いかと思う struct XEventSource { listeners : Vec<Box<dyn Handler>>, ... } trait Handler { fn handle(ev: &XEvent) -> () } impl XEventSource { fn addLisnter(&mut self, listener : Box<dyn Handler>) -> () { self.listeners.push(listener); } fn emit(&self) -> () { XEvent ev = ...; for listener in listeners.iter() { listener.handle(&ev); } } } みたいに作ると、利用者が好きに作った構造体でもHandlerをimplすればlistenersに足せる ジェネリクスだとイベントリスナの実際の型1つしかaddできないので不便 >>402 実行時に型を振り分けるとなると仮想関数テーブルを辿る必要があるんで実行時コストが少し増えるよ。 (Rust では仮想関数って言わないのかな? 正確な用語がわからん。) トレイトを実装している型を実際には一種類しか使わないのだったら、 実行時間を除けば見かけ上の動作で違いはないかもしれんな。 でも基本的にはやりたいことを出来る範囲で制約は厳しい方がいい。 間違いの検出される可能性が高まるから。 制約をどのように表現するかというのはプログラミング言語の設計においては重要なトピックで、 構造化プログラミングが提唱されたのも goto だと制御をどこへ移動するのか制約を付けられないってのがある。 さらにそれを発展させた形として型で制約を付けようってのが色々と考えられてきたし、 Rust では更にオブジェクトの寿命に制約を付けようという考えが実現された。 その関数では何ができるのか、そして「何をしてはいけないのか」ってのを考えると Rust らしいプログラムが出来ると思う。 APIサーバーでJSON受け取るときに値の型が違ったりオーバーフローするときってどうしてる? serde_json::from_str で構造体の属性でエラーメッセージとかつけれたらいいのにな from_strの結果そのまま使ってるけどダメなの シンタックスエラーとか含めると大変じゃない 海外向けサーバーだったらいいけど日本向けサーバーの場合は? serde_jsonのエラーメッセージcustomizableじゃないから辛い serde_json::Error を見ると行と列と大雑把な原因はとれるみたい 細かくやるなら置換するしかなさそうだね reached the configured maximum number of stack frames でスタックフレームの制限にかかるんだけどオプションとかで変えれる? impl<'_, T> Drop for std::collections::vec_deque::Drain<'_, T> こういう風にちゃんとパス書かれたのもあれば、デフォルトインポートされてないのに省略されてる型あるけどどうなってるの? https://doc.rust-lang.org/std/ops/trait.Drop.html フルパス書かなくてもいいように mod.rsに指定されてるものとされてないもの それが必要な理由は?ここはお前の便利帳じゃねーんだから 有益な使い方が有れば紹介してから聞け >>412 Yコンビネータ Rust で適切に型がつけられるかどうか知らんけど >>413 データ入ったVecと各種定数とメモ化用のmutなHashMap使ったDFSするときとか、引数がむっちゃ長くなるんです >>414 全然わからんのであきらめます・・・ Copyでの関数呼び出しとポインタ作成ってコスト的にはプリミティブのどの型からが処理重い? ここらへんCSの知識ないからわかんない Rust仕事で使ってる人〜 ウチはコロナの影響でプロジェクト吹き飛んだよん( ;∀;) 組み込みで試験的に導入したけどムズイ まあ慣れの問題もあるのだろうけど ATS2ってRust以上にドキュメントが少なくてHaskell以上に難解なアレじゃないですかやだー! Rust界隈で一番貢献度高いのってAlexとかになるかな? Microsoftに期待してるんだが今はそれどころじゃ無さそう 勉強がてらこちらの二分探索木を真似してみたのですが、コンパイルエラーが出てしまいます。 https://codereview.stackexchange.com/questions/133209/binary-tree-implementation-in-rust playgroundで試してみた結果がこれです。 https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=fc1fe0d2a4c39c6b28d017539419fa2a どうやら古いRustならコンパイルが通るようなのですが、今のRustでコンパイルを通すにはどうすればよいのでしょうか? 非常に良いと思います。flagの意図を読み解くのが少し難しいくらいです。 確かにflagが読みづらいからコメントは欲しいかな 個人的にはuse Exp::*;とExp::V => Exp::Valueにするのとテストケース増やしてmod testsにするかな let exp = Value("MITSU").add(Value("MITSU")).add(Value("MITSU")).eql(Value("CORONA")); let solver = Solver::new(exp); // prints solved exp solver.solve(); 最初のインスタンスは読みにくいからこうするかも、それかマクロかビルダー作るか トレイトって機能を追加するときどういう機能であるかの特徴を一見して分かりやすくするためだけのもの? >>433 とりあえずはJavaやC#のインターフェースっぽいものとして捉えておけばいいんじゃないのかな やってるうちに違いも分かってくる思うので これライフタイム記述を省略できないのなんで? https://git.io/JfL6t 省略してコンパイラ通るけどstableは無理なん? 関数内で同じ一連の処理を複数回実行するときマクロにまとめるのが一般的?それともクロージャ? 他にやりかたある? https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=30449f979231232b68016cab5cd1fb1e https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=e5fc7f66785bb3794df19104d5c479ff >>438 関数 あとサンプルだからかもしれないけど spilt_whitespace()とかでイテレータ使ったほうが読みやすい https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=b03bef5cb6f98821032c5fb1cce618a1 そのコードは実際に使うコードじゃなくてさあ、変数が何個もあったりすると関数切り出しは引数が地獄になるじゃん その例でマクロかクロージャの二択ならクロージャだけど >>438 のは外側の変数をキャプチャすることで複雑化してるから&tangoを渡すようにする https://play.rust-lang.org/?version=stable& ;mode=debug&edition=2018&gist=ec760be4190e2ad4ab21fbea3c84b0ed そうすると結局クロージャも関数と同じように適切なシグニチャを考える必要があるから 関数化に比べて楽ってことはないんじゃないかと思う 公式のGithubにrustlingsっていう簡単な練習問題がある The Bookを読んだ後に基本文法をおさらいしたい人向け https://github.com/rust-lang/rustlings ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる