## 所有権とは?
- [[スタック]]と[[ヒープ]]
- [[スタック]]上のデータサイズはすべて既知の固定サイズでなければいけない
- [[ヒープ]]が遅いのは[[ポインタ]]を頼りに目的の領域まで移動(検索?)する必要があるから
- 規則
- [[Rust]]の各値は、所有者と呼ばれる変数と対応している
- いかなる時も所有者は1つ
- 所有者がスコープから外れたら値は破棄される
- `push_str`でStringに後ろに文字列リテラルを追加
- [[Rust]]では変数がスコープから抜けるとき [[Dropトレイト]]の`drop`が自動で呼ばれる
- ここでメモリの返還をしている
Stringの中身について。`ptr`、`len`、`capacity`を確認できる。
![[Pasted image 20221105212418.png]]
上記 [[VSCode]]で`s2`がデバッガーに出現しないのは、`s1`も`s2`も`s1`が確保した[[ヒープ領域]]を参照しているからなのか?
```rust
fn main() {
let s1 = String::from("hello");
println!("{}", s1);
let s2 = s1.clone();
println!("{}", s2);
}
```
としても`s2`は出現しない..。(ただ、[[Rust]]の文法的には[[ディープコピー]]と見なしていいはず)
```rust
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("{}", s1);
println!("{}", s2);
}
```
これだと最終行で出現する! もしかして、異なる[[ヒープ領域]]を参照させる(確保する)必要がないのであれば、同一の[[ヒープ領域]]を使うから`s2`の実体が現れないのでは...!?
話を戻す。
```rust
fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s2);
}
```
`main`関数では`s1`と`s2`が存在し、それぞれスコープから抜ける瞬間がくる。しかし、両者の[[ヒープ領域]]は同一のため、メモリの二重開放エラーとなってしまい、メモリー破壊につながる。
ただ、[[Rust]]は実際にそのようなことはしない。`let s2 = s1`の段階で`s1`は無効と判断され、スコープを抜けてもメモリ解放を行わなくなるから。[[所有権]]が移る処理を[[ムーブ]]といい、『`s1`は`s2`に[[ムーブ]]された』という。
- [[Rust]]では自動的にデータの[[ディープコピー]]が行われることは絶対にない
- 整数のようなprimitive型に[[ムーブ]]は発生しないので、束縛も無効化されない
- そのようなものは[[Copyトレイト]]が実装されている。
- 具体例
- 整数型
- 論理値型
- 浮動小数点型
- 文字型`char`
- [[タプル (Rust)|タプル]] (要素がすべて[[Copyトレイト]]を実装している場合のみ)
- 関数の[[実引数]]に[[Copyトレイト]]を実装していない型の変数を渡すと[[ムーブ]]する
- 関数呼び出し後、[[実引数]]は使えない
- 関数の戻り値でも[[ムーブ]]する
関数の[[実引数]]に指定した変数を、関数呼び出し後も遣いたいことは多いはず。ただ、そのために==仮引数を関数から常にreturnする==のは非常にいただけない。
## 参照と借用
[[参照]]の例。
```rust
fn main() {
let s = String::from("hello");
print(&s);
println!("{:?}", s);
}
fn print(some_thing: &str) {
println!("{:?}", some_thing);
}
```
この場合、`some_thing`がスコープを抜けても( = print関数を抜けても)、`some_thing`が指すものをdropすることはない。つまり、`print`関数が終了しても、`some_thing`が指す[[ヒープ領域]]、すなわち`main`関数の`s`は無効化されない。
- [[借用]]
- [[借用]]した[[仮引数]]に変更を加えたい場合はそれぞれに`mut`の追加が必要
```diff
fn main() {
- let s = String::from("hello");
+ let mut s = String::from("hello");
- change(&s);
+ change(&mut s);
}
- fn change(some_string: &String) {
+ fn change(some_string: &mut String) {
some_string.push_str(", world");
}
```
- [[可変参照#可変参照 の制約]]
- [[特定のスコープである特定データに対して1つしか可変参照を持てない]]
- [[特定のスコープである特定データに対する不変参照が存在する場合は可変参照を持てない]]
- [[ダングリングポインタ]]は仕組み上発生しない
以下はコンパイルエラーになる。
```rust
fn main() {
let r = dangle();
// rが指す領域はdangle関数を抜けるときに解放済なので危険!!!
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
```
関数では[[参照]]ではなく実体を返すようにすればいい。ということは[[Rust]]で[[構造体 (Rust)|構造体]]を生成する関数は実体を返すのが基本になるのかな?
## スライス型
- `&s[0..2]`がスライス
- `&str`はスライス = リテラル