Rustのオーナーシップ　その3

# The Slice Type

これは以下の記事を翻訳して、自分なりに整理したものです。

https://doc.rust-lang.org/book/ch04-03-slices.html

所有権を持たないもう1つのデータ型はスライスです。スライスを使用すると、コレクション全体ではなく、コレクション内の隣接する要素のシーケンスを参照することが出来る。

文字列を受け取り、その文字列で最初に見つかった単語を返す関数を記述する。関数が文字列内にスペースを見つけられない場合、文字列全体が1つの単語である必要があるため、文字列全体が返される。

```
fn first_word(s: &String) -> ?
```

この関数を考えてみる。

```リスト4-7
fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}
```

要素ごとにString要素を調べて、値がスペースかどうかを確認する必要があるため、as_bytesメソッドを使用してStringをバイトの配列に変換する。

```
let bytes = s.as_bytes();
```

次に、iterメソッドを使用して、バイトの配列に対してイテレータを作成する。

```
for (i, &item) in bytes.iter().enumerate() {
```

iterはコレクションの各要素を返すメソッドであり、列挙型はiterの結果をラップして、代わりに各要素をタプルの一部として返す。 enumerateから返されるタプルの最初の要素(i)はインデックスで、2番目の要素(&item)は要素への参照。参照を取得するため、&がつく。
forループの中でスペースを示すバイトを探す。見つけたらそのインデックスを返す。それ以外の場合は文字列全体の長さを返す。

```
        if item == b' ' {
            return i;
        }
    }

    s.len()
```

しかし、この値は入力文字列とは別の値なので、今後も保証されるとは限らない。
以下のコードを考えてみる。

```
fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s); // word will get the value 5

    s.clear(); // this empties the String, making it equal to ""

    // word still has the value 5 here, but there's no more string that
    // we could meaningfully use the value 5 with. word is now totally invalid!
}
```

s.clear()の後にwordを使用してもエラーにはならない。しかし、sとwordが関連付けられていないため、s.clear()してもwordには5の数字が入ったままになる。
sとwordが同期しなくなるのでエラーとなりやすい。
以下の場合はより深刻になる。

```
fn second_word(s: &String) -> (usize, usize) {
```

開始インデックスと終了インデックスを返す関数である。
これでは不安定な変数がさらに増えてしまう。

**Rustにはこれを解決する方法がある。文字列スライスである。**

## String Slices

文字列スライスは文字列の一部への参照であり、次のようになる。

```
    let s = String::from("hello world");

    let hello = &s[0..5];
    let world = &s[6..11];
```

[0..5]のようなものが付いているが、これは文字列の一部に対する参照である。
[starting_index..ending_index]を指定することにより、角かっこ内の範囲を使用してスライスを作成できる。
starting_indexはスライスの最初の位置であり、ending_indexはスライスの最後の位置より1つ大きくなる。
内部的に、スライスデータ構造は、スライスの開始位置と長さを格納する。これは、ending_indexからstarting_indexを引いた値に対応する。そのため、let world = &s[6..11];の場合、worldは、長さが5のsの7番目のバイト（1から数えて）へのポインターを含むスライスになる。

![](https://doc.rust-lang.org/book/img/trpl04-06.svg)

Rustの.. range構文を使用して、最初のインデックス（ゼロ）から開始する場合は、2つのピリオドの前の値をする。
以下は同じ事を表す。

```
let s = String::from("hello");

let slice = &s[0..2];
let slice = &s[..2];
```

同様に、スライスに文字列の最後が含まれている場合、末尾の文字を削除することが出来る。
以下は同じ事を表す。

```
let s = String::from("hello");

let len = s.len();

let slice = &s[3..len];
let slice = &s[3..];
```

両方の値を削除して、文字列全体のスライスを取得することもできる。
以下は同じ事を表す。

```
let s = String::from("hello");

let len = s.len();

let slice = &s[0..len];
let slice = &s[..];
```

*文字列スライスはUTF-8文字の境界である必要がある。マルチバイトの途中に文字列スライスを指定するとエラーでプログラムが終了する。ここではASCII文字のみを想定する*

スライスを使用してfirst_wordを書き換えてみる。
**「文字列スライス」を表すタイプは、&strとして記述する。**

```
fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}
```

これで、first_wordを呼び出すと、基になるデータに関連付けられている単一の値が返される。値は、スライスの開始点への参照とスライス内の要素数で構成されている。

スライスはsecond_wordでも機能する。

```
fn second_word(s: &String) -> &str {
```

このfirst_wordを上のmain関数のように使用するとエラーとなる。文字列スライスはこのエラーを早期に発見することが出来る。

![コメント 2020-09-05 095824.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624329/39e7531e-fcb3-1cec-8df0-4e3c690c628f.jpeg)

Rustの借用ルールから、変更可能な参照のオーナーシップはwordにあるため、参照元のsへの変更はエラーとなる。

### String Literals Are Slices

バイナリ内に格納されている文字列リテラルについて話したことを思い出してください。スライスについて理解したので、文字列リテラルを適切に理解できます。

```
let s = "Hello, world!";
```


ここでのsのタイプは＆strです。これは、バイナリの特定のポイントを指すスライスです。これは、文字列リテラルが不変である理由でもあります。 ＆strは不変の参照です。

### String Slices as Parameters

リテラルと文字列値のスライスを取得できることを知っていると、first_wordがさらに改善されます。それが署名です。

```
fn first_word(s: &String) -> &str {
```

＆String値と＆str値の両方で同じ関数を使用できるため、以下の様に書けます。

```
fn first_word(s: &str) -> &str {
```

文字列スライスがある場合は、直接渡すことができます。文字列がある場合は、文字列全体のスライスを渡すことができます。文字列への参照の代わりに文字列スライスを取得する関数を定義すると、APIが機能を失うことなく、より一般的で便利になります。

```
fn main() {
    let my_string = String::from("hello world");

    // first_word works on slices of `String`s
    let word = first_word(&my_string[..]);

    let my_string_literal = "hello world";

    // first_wordは文字列リテラルのスライスで機能します
    let word = first_word(&my_string_literal[..]);

    // 文字列リテラルはすでに文字列スライスであるので、これはスライス構文なしでも機能します！
    let word = first_word(my_string_literal);
}
```

## Other Slices

文字列スライスは、ご想像のとおり、文字列に固有のものです。しかし、より一般的なスライスタイプもあります。この配列を考えてみましょう

```
let a = [1, 2, 3, 4, 5];
```


文字列の一部を参照したい場合と同様に、配列の一部を参照したい場合があります。次のようにします。

```
let a = [1, 2, 3, 4, 5];

let slice = &a[1..3];
```

このスライスのタイプは＆[i32]です。これは、最初の要素への参照と長さを格納することにより、文字列スライスと同じように機能します。この種類のスライスは、他のあらゆる種類のコレクションに使用します。

## Summary

所有権、借用、およびスライスの概念により、コンパイル時にRustプログラムのメモリの安全性が確保される。 Rust言語を使用すると、他のシステムプログラミング言語と同じようにメモリ使用量を制御できますが、データの所有者がスコープ外に出たときにデータの所有者が自動的にクリーンアップするため、追加のコードを記述してデバッグする必要がない。

所有権は、Rustの他の多くの部分が機能する方法に影響を与えるため、残りの部分では、これらの概念についてさらに説明する。