はじめに
NO IMAGEThe Rust Programming Language 日本語版 - The Rust Programming Language 日本語版
を読んでいる
今日はなにより一番始めにやることにした
今日読む場所
NO IMAGEライフタイムで参照を検証する - The Rust Programming Language 日本語版
お勉強
メモ
mplブロック内のメソッドシグニチャでは、参照は構造体のフィールドの参照のライフタイムに紐づいている可能性と、 独立している可能性があります。加えて、ライフタイム省略規則により、メソッドシグニチャでライフタイム注釈が必要なくなることがよくあります。
- うおーーーしょっぱなから混乱するぜ
impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self, announcement: &str) -> &str {
// "お知らせします: {}"
println!("Attention please: {}", announcement);
self.part
}
}
2つ入力ライフタイムがあるので、コンパイラは最初のライフタイム省略規則を適用し、 &selfとannouncementに独自のライフタイムを与えます。それから、 引数の1つが&selfなので、戻り値型は&selfのライフタイムを得て、 全てのライフタイムが説明されました。
- ?????????
- さっきのルールなら2つライフタイムがあるなら2つ適応されるのでは???
- それができないなら明記しないといけないのでは???
- geminiに聞いてナルホドーーーーーーーとなった
3番目の規則は、複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが&selfや&mut selfだったら、 selfのライフタイムが全出力ライフタイム引数に代入されるというものです。 この3番目の規則により、必要なシンボルの数が減るので、メソッドが遥かに読み書きしやすくなります。
- 前回適応されなかったこれを適応できるらしい
| パターン | 実装コードの書き方 | コンパイラへのメッセージ(解釈) |
|---|---|---|
| 1. 普通の実装 | impl Trait for Type |
「この完成された型に、この機能を付けます」 |
| 2. ジェネリクス | impl<T> Trait for Type<T> |
「任意の型 T を中に入れている Type に対して機能を付けます」 |
| 3. ライフタイム | impl<'a> Trait for Type<'a> |
「外部の寿命 'a に依存している Type に対して機能を付けます」 |
- このへんが混乱していたなー
ジェネリックな型引数、トレイト境界、ライフタイムを一度に
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(
x: &'a str,
y: &'a str,
ann: T,
) -> &'a str
where
T: Display,
{
// "アナウンス! {}"
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
- えーてか
<'a, T>って書けるんかい T: Displayって書いてあるからディスプレイトレイトを持ってなきゃいけないってやつね- これって
<'a,'b,T,U>とかで書けるの?
// ✅ 正しい:ライフタイムが先
impl<'a, 'b, T, U> MyStruct<'a, 'b, T, U> { ... }
// ❌ 間違い:型を先に書くとエラー
impl<T, U, 'a, 'b> MyStruct<'a, 'b, T, U> { ... }
- こういう順番らしい
- へぇ~
信じられないかもしれませんが、この章で議論した話題にはもっともっと学ぶべきことがあります:
- ナニーーーーーーー
自動テストを書く
- お、テスト
- テストをちゃんと書けばあらゆるところの思考を減らせるから好きなんだよなー
- 書き方をもうちょっと学びたい
まとめ
- ライフタイム、思ったより複雑だった
- ジェネリクスと同じように書けて、同じ
<>内に書くということがわかった - 借用をしている場合のみライフタイムを記述する
- 省略も明示的に引数と同じ戻り値の数だった場合のみできる
- トレイトの場合は
&selfだけ特別対応なので省略できる&selfと同じライフタイムになる
- 次はここ