はじめに
自分はwebサービスを提供したいと考えており、そんな落ちてはいけないwebサービスにぴったりだと思ったためRustを選びました。
これから毎日1つづつ勧めていけたらなと思っています。
スライス型
スライスとは連続した要素を参照するものです。
fn first_word(s: &String) -> usize {
let bytes = s.as_bytes();//バイト列に変換
for (i, &item) in bytes.iter().enumerate() {//iterメソッドでイテレーター(不空数のデータを保持するオブジェクト)を生成
if item == b' ' {
return i;
}
}
s.len()
}
しかしStringと完全に切り放されているため有効である保証がありません。
文字列スライス
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
}
helloという変数は[0..5]つまりStringの0~5へ参照するものです。長さは5-1=4なので長さは4になります。

範囲指定方法
添え字0から始めたい場合は[..2]と書くことも可能です。
逆に最後まで含めたい場合は[2..]と書くこともできます。
全部選択する場合は[..]と省略できます。
注意:ASCII文字ではないマルチバイト文字(複数のバイトで1文字を表すもの)の場合、文字の境界線で行わなかった場合エラーが起きます。
今魔の知識を使って、先ほどのコードを改良すると
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[..]
}
このようにすることのメリットはStringへの参照が有効なままであることをコンパイルが保証しているからです。そして前のコードの場合、空白の文字列に対してやったことによりエラーが発生していました。しかしスライスを使用することでコンパイルエラーが起きるため迅速にエラーが判明します。
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[..]
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // error! (エラー!)
println!("the first word is: {}", word);
}
このコードを実行すると以下のようなエラーが発生します。このようにRustはある種のエラーを全てコンパイル時に排除してくれたりAPIを使いやすくできます。
$ cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
(エラー: 不変として借用されているので、`s`を可変で借用できません)
--> src/main.rs:18:5
|
16 | let word = first_word(&s);
| -- immutable borrow occurs here
| (不変借用はここで発生しています)
17 |
18 | s.clear(); // error!
| ^^^^^^^^^ mutable borrow occurs here
| (可変借用はここで発生しています)
19 |
20 | println!("the first word is: {}", word);
| ---- immutable borrow later used here
(不変借用はその後ここで使われています)
For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` (bin "ownership") due to 1 previous error
引数としての文字列スライス
上記のコードではfn first_word(s: &String) -> &str {と書かれていますが
fn first_word(s: &str) -> &str {とすることで柔軟性が高くなり、 同じ関数を&String値と&str値両方に使えるからです。
他のスライス
一般的なスライス型も存在し同じように使用することができます。以下の場合&[i32]になります。
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);
まとめ
次回は構造体を定義し、インスタンス化するをしていきたいです。