今日は皮膚科に行ったり
diary
game
昨晩はゴッドフィールドをプレイしていた。ルールを大凡把握できた。
APEXをインストールした。チュートリアルを終えた。
dermatology
午前中に皮膚科に行った。
ステロイド治療をすることになった。かなり即効性がある。
long nap
五時間昼寝していた。
mercari
ウェブポンでダブった製品をメルカリに出品。
そのコラボ相手の人気はそれほど高くないので、売れる見込みは少ないが、 市場価値としてこうあってほしい金額で出しておく。
ウェブポンの場合、転売という表現はあまり該当しない。ああいった謎の景品の場合、こうでもしないと価値が定まらない。
あと、反応を見ていると、コラボ相手のファン層がメルカリとか転売とかにすごく嫌な感情を抱き、それが先行し過ぎている人がちらほら見えた。 それはその層特有ではなく、広くそういうものなのかもしれない。 (ファン心理として認められないものを売ることがあるのは確か。例えばサイン色紙とか。)
そういった反応を頭が悪いというつもりはないし、転売は良い行為だと両手を上げるわけでもない。 ただ、市場に出回る機会すらないようなコラボ商品という物の価値はとてつもなく低いか、とてつもなく高いかで、つまり値段が付けられないものであり、結局、そのコラボ相手の価値を測れないものであることを示してしまう。
今日の勉強
rust
TRPL pp.216-225
関数のライフタイム注釈の書き方
fn function_name <'a> (x: &'a t, y: &'a t) -> &'a t {
...
}
コンパイラに型注釈が教えること:
- 何らかのライフタイム
'a
に対して- その引数は少なくともライフタイム
'a
と同じだけ生きること - その返り値もまた少なくともライフタイム
'a
と同じだけ生きること- 引数のうち小さいほうに等しい具体的なライフタイムになる
- その引数は少なくともライフタイム
いかなる値のライフタイムも変更していない。 むしろ借用チェッカーはこれらの制約を守らない値をすべて拒否するべきと指定。 引数のうち小さいほうに等しい具体的なライフタイムになるので、無効になる可能性があるので、その場合は拒否する。
関数は正確な生存期間を知る必要はなく、何らかのスコープが'a
に代替され、このシグニチャを満足することだけを知っている必要がある。
手動でライフタイム注釈をする必要がある理由
注釈は関数シグニチャに嵌り、関数本体には嵌らない
コンパイラは、
- 関数内のコードを解析できる一方で、
- 外から持ち込まれた参照や外へ持ち出される参照がある場合、それだけの情報でライフタイムを解決することはほぼ不可能
- 例外としてライフタイム省略規則があり、解決できる
ライフタイム引数を指定する必要のある手段は関数が行っていることによる
関数が参照を返す際、戻り値のライフタイム引数は、引数のうち、どれかのライフタイム引数と一致する必要がある
- そうでなければ、関数内で生成された値への参照であり、それは末端のスコープで抜け、片づけられ、タングリング参照をうむ
- その場合は所有されたデータ型を返せ
- そうでなければ、関数内で生成された値への参照であり、それは末端のスコープで抜け、片づけられ、タングリング参照をうむ
究極的にライフタイム記法は、関数の色々な引数と戻り値のライフタイムと接続することに関する
- 繋がりができたら
- メモリ安全な処理を許可するのに十分な情報がコンパイラにはあり
- メモリ安全性を損なうタングリングポインタを生成するであろう処理を不認可する
- 繋がりができたら
構造体にライフタイム
構造体に参照を保持させるには、ライフタイム注釈をつける必要がある
struct StructName <'a> {
field: &'a t
}
この注釈は、StructNameのインスタンスがフィールドに保持している参照よりも長生きしないことを意味する。
ライフタイム省略規則
ライフタイム注釈なしでコンパイルできるケースは歴史的な経緯による
- 開発者が予測可能で決定的なパターンをコンパイラのコードに落とし込んで
- 借用チェッカーがライフタイムを推論できるようになり、明示的な注釈を必要としなくなった。
ライフタイム省略規則:
- コンパイラの参照解析に落とし込まれたパターンのこと
- コンパイラが考慮する一連の特定のケース
- 完全な推論を提供しない
- 曖昧性があるなら推論するのではなくエラーを与える
用語:
- 引数のライフタイムを「入力ライフタイム」といい
- 戻り値のライフタイムを「出力ライフタイム」という
3つの規則。上から順に適用される。
- 参照である各引数は、独自のライフタイム引数を得る
- 1つだけ入力ライフタイム引数があるなら、そのライフタイムを全ての出力ライフタイム引数に代入する
- 複数の入力ライフタイム引数があるが、メソッドなのでそのうち一つが
& self
や&mut self
なので、self
のライフタイムが全出力ライフタイム引数に代入される
メソッドシグニチャのライフタイム引数
ジェネリックな型引数の場合と同じ記法
impl <'a> StructName <'a> {
...
}
- 参照が構造体のフィールドの参照のライフタイムに紐づくか独立しているかの可能性があること
- 省略規則でライフタイム注釈が必要なくなることがよくあること
‘static
- 特殊なライフタイム
'static
は、プログラム全体の期間を指す。- 例えば、文字列リテラルは全てこれ
- なぜなら、プログラムのバイナリに直接格納され、常に利用可能だから。
- 例えば、文字列リテラルは全てこれ
注意: エラーメッセージで'static
ライフタイムの仕様を提言されても、本当に全期間生きてほしいかどうかを考慮せよ
なぜならほとんどの場合、その問題は以下のいずれかである。
- タングリング参照を生成しているか
- 利用可能なライフタイムが不一致しているか