🦀

Rustわからん

2021/05/04に公開

Rust難しい

わからないことを書いていく。不定期に更新。自分用メモなのであしからず。

iter()into_iter() の違い

https://dawn.hateblo.jp/entry/2017/07/24/165933 を読むと良い。

  • iter() は move しない。参照のコレクションをIteratorとして作成する。
  • into_iter() は move する。値のコレクションをiteratorとして作成する。

Box<dyn Error> について

https://text.baldanders.info/rust-lang/error-handling/ を読むと良い。

エラーを汎化するときに使う。
以下のようにはかけないが、

fn parse_from_stdin() -> Result<u32, std::num::ParseIntError> {
    let mut buf = String::new();
    std::io::stdin().read_line(&mut buf)?; //Compile error: `?` couldn't convert the error to `std::num::ParseIntError`
    buf.trim().parse::<u32>()
}

以下のようにはかける。

fn parse_from_stdin() -> Result<u32, Box<dyn std::error::Error>> {
    let mut buf = String::new();
    std::io::stdin().read_line(&mut buf)?;
    let n = buf.trim().parse::<u32>()?;
    Ok(n)
}

fn main() {
    println!("{:?}", parse_from_stdin());
}

なぜか。 Rust Compiler は関数の戻り値に必要なサイズを知りたいがために、具体的な型を戻り値の型に示すことを要求する。例えば Trait を戻り値の型として設定することができない。
これでは困ることもあるので、 Box でくるんで戻り値とすればよい。 box はheapにあるメモリの参照を表す。参照は statically-known なサイズなので compiler は許してくれる。これボクシングじゃね?と思ったが、だから Box なのか・・・
Rustはできるだけheapにメモリを確保することを明示的にしたいので、このようなことをしたい際には dyn キーワードを付ける必要がある。

https://doc.rust-lang.org/stable/rust-by-example/trait/dyn.html

&'static について

https://laysakura.github.io/2020/05/21/rust-static-lifetime-and-static-bounds/ を読むと良い。

プログラム中ずっと生き残るライフタイムを示す。だけどそれだけじゃないらしい。ライフタイム境界が関連する。トレイト境界とも関連あり?

dyn について

TBA

トレイト境界について

T: Ord + DebugT という型は何でも良いが、 「 OrdDebug は実装すること」という制約を表す。多重継承の代わりか?

lifetime annotationについて

https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html を読むと良い。
以下はコンパイルできない。

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

なぜなら、戻り値となるのが xy かコンパイル時点ではわからないため。

以下は通る。

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

&'a とつけることにより、 xy も同じlifetimeを持つことがわかるため。

// コンパイルエラーにするくらいなら勝手にアノテーションとかつけてくれればいいのに・・・と思ったが、そうも行かない理由があるらしい。
// https://stackoverflow.com/questions/31609137/why-are-explicit-lifetimes-needed-in-rust/31612025#31612025

なお、 Struct がreferenceを持つ際にも、 Lifetime annotationが必要である。

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
}

lifetime elisionについて

TBA

&self&mut self について

これらはいわゆる糖衣構文。
https://doc.rust-lang.org/rust-by-example/fn/methods.html を読むと良い。

  • &selfself: &Self と同値。Selfは Caller Object の型
  • &mut selfself: &mut Self と 同値

Struct が文字列を持つときのイディオムについて

以下を読むと良い。結構深遠な問題っぽい。

Cow を使うやり方はちょっと自分には早そう。カリカリチューニングが必要な場面でも無ければ、 StringT: Into<String> か。

Genericsについて

以下を読むと良い、と言いたいところだが、読んでもよくわからなかった。。

https://doc.rust-lang.org/rust-by-example/generics/gen_fn.html

こちらのほうがわかりやすい。

https://doc.rust-jp.rs/book-ja/ch10-00-generics.html

Qiita記事のこちらも良さそう。

https://qiita.com/quasardtm/items/09952838a6ee9582db1d

Discussion