Rustわからん
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 キーワードを付ける必要がある。
&'static について
https://laysakura.github.io/2020/05/21/rust-static-lifetime-and-static-bounds/ を読むと良い。
プログラム中ずっと生き残るライフタイムを示す。だけどそれだけじゃないらしい。ライフタイム境界が関連する。トレイト境界とも関連あり?
dyn について
TBA
トレイト境界について
T: Ord + Debug は T という型は何でも良いが、 「 Ord と Debug は実装すること」という制約を表す。多重継承の代わりか?
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
}
}
なぜなら、戻り値となるのが x か y かコンパイル時点ではわからないため。
以下は通る。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
&'a とつけることにより、 x も y も同じ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 を読むと良い。
-
&selfはself: &Selfと同値。Selfは Caller Object の型 -
&mut selfはself: &mut Selfと 同値
Struct が文字列を持つときのイディオムについて
以下を読むと良い。結構深遠な問題っぽい。
- https://users.rust-lang.org/t/idiomatic-string-parmeter-types-str-vs-asref-str-vs-into-string/7934
- https://qiita.com/Kogia_sima/items/6899c5196813cf231054
Cow を使うやり方はちょっと自分には早そう。カリカリチューニングが必要な場面でも無ければ、 String か T: Into<String> か。
Genericsについて
以下を読むと良い、と言いたいところだが、読んでもよくわからなかった。。
こちらのほうがわかりやすい。
Qiita記事のこちらも良さそう。
Discussion