スライス(&str / &[T])
スライスはコレクションの一部への参照で、所有権を持ちません。文字列スライス(&str)と配列スライス(&[T])の2種類があります。
構文
// 文字列スライス let s: &str = "hello"; // 文字列リテラルは&strです。 let slice = &string[開始..終了]; // Stringから部分スライスを取得します。 // 配列スライス let slice: &[i32] = &array[開始..終了]; let full: &[i32] = &array[..]; // 全体のスライスです。
スライス記法一覧
| 記法 | 概要 |
|---|---|
| &s[0..5] | インデックス0から4まで(5は含まない)のスライスです。 |
| &s[..5] | 先頭から4まで(開始省略)のスライスです。 |
| &s[3..] | インデックス3から末尾まで(終了省略)のスライスです。 |
| &s[..] | 全体のスライスです。 |
| &str | 文字列スライス型です。文字列リテラルの型でもあります。 |
| &[T] | 型Tの配列スライス型です。 |
サンプルコード
sample_slice.rs
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i]; // 最初の空白の前までを返します。
}
}
&s[..] // 空白がなければ全体を返します。
}
fn sum_slice(nums: &[i32]) -> i32 {
nums.iter().sum()
}
fn main() {
// 文字列スライス
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
println!("{} {}", hello, world); // 『hello world』と出力されます。
let word = first_word(&s);
println!("最初の単語: {}", word); // 『hello』と出力されます。
// 配列スライス
let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
println!("{:?}", slice); // 『[2, 3, 4]』と出力されます。
println!("合計: {}", sum_slice(&a)); // 『15』と出力されます。
}
rustc slice.rs ./slice hello world 最初の単語: hello [2, 3, 4] 合計: 15
slice2.rs — スライスのメソッド操作
fn main() {
let scores = [85, 92, 78, 96, 88, 71, 95];
// 部分スライスを取得します。
let top3 = &scores[..3];
let last3 = &scores[scores.len() - 3..];
println!("top3: {:?}", top3); // [85, 92, 78]
println!("last3: {:?}", last3); // [71, 95] ← 実際は [88, 71, 95]
// スライスのメソッドを使います。
println!("len: {}", scores.len());
println!("contains 96: {}", scores.contains(&96));
println!("iter sum: {}", scores.iter().sum::<i32>());
// windows / chunks でまとめて処理します。
println!("windows(3):");
for w in scores.windows(3) {
println!(" {:?}", w);
}
println!("chunks(3):");
for chunk in scores.chunks(3) {
println!(" {:?}", chunk);
}
}
rustc slice2.rs ./slice2 top3: [85, 92, 78] last3: [88, 71, 95] len: 7 contains 96: true iter sum: 605 windows(3): [85, 92, 78] [92, 78, 96] [78, 96, 88] [96, 88, 71] [88, 71, 95] chunks(3): [85, 92, 78] [96, 88, 71] [95]
slice3.rs — 可変スライスとsort/split
fn main() {
let mut names = ["Vegeta", "Son Goku", "Piccolo", "Krillin", "Gohan"];
// 可変スライスをソートします。
names.sort();
println!("sorted: {:?}", names);
// splitで分割します(元の配列は変わりません)。
let (first_half, second_half) = names.split_at(2);
println!("first: {:?}", first_half);
println!("second: {:?}", second_half);
// iterで変換します。
let upper: Vec<String> = names.iter().map(|s| s.to_uppercase()).collect();
println!("upper: {:?}", upper);
}
rustc slice3.rs ./slice3 sorted: ["Gohan", "Krillin", "Piccolo", "Son Goku", "Vegeta"] first: ["Gohan", "Krillin"] second: ["Piccolo", "Son Goku", "Vegeta"] upper: ["GOHAN", "KRILLIN", "PICCOLO", "SON GOKU", "VEGETA"]
概要
スライスは元のデータへの参照であるため、コピーは発生しません。関数引数に『String』の代わりに『&str』を使うと、文字列リテラルとStringの両方を受け取れるためより汎用的な設計になります。
マルチバイト文字(日本語など)を含む文字列をバイト境界ではないインデックスでスライスすると実行時パニックになります。文字単位で操作する場合は『chars()』メソッドを使用してください(String::chars())。
スライスのライフタイムは参照元のデータと結びついており、参照元が解放されるとスライスも無効になります。詳細はライフタイム('a)を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。