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