コンテンツにスキップ

Rustの文字列

テキストの扱いは、Rustがほかの言語と違うと感じる最初のポイントのひとつです。その主な理由は、Rustには文字列の型が2つあるからです。でも、なぜ2つあるのかがわかれば、もう混乱することはありません。

  • &str(「文字列スライス」)— どこかにすでに存在しているテキストです。たいていはコードの中に直接書いたものです。サイズは固定で、伸ばすことはできません。
  • String — 所有権を持った、伸ばせるテキストです。あとから文字を追加でき、ヒープ(heap)というメモリ領域に置かれます。
fn main() {
let literal: &str = "こんにちは"; // 文字列スライス
let owned: String = String::from("こんにちは"); // 所有権を持つ String
println!("{literal} / {owned}");
}
▶ 実際に試してみよう

簡単な目安:決まったテキストを表示するだけなら、"こんなふうに" 書いたもの(&str)で十分です。実行中にテキストを組み立てたり、伸ばしたり、変更したりする必要があるなら、String を使いましょう。

fn main() {
let mut greeting = String::from("こんにちは");
greeting.push_str("、世界"); // &str を追加する
greeting.push('!'); // 1文字(char)を追加する
println!("{greeting}");
}

実行結果:

こんにちは、世界!
▶ 実際に試してみよう

文字列は + でつなげることもできますし、format! を使うこともできます(たいていは format! のほうがわかりやすいです)。

fn main() {
let first = String::from("こんにちは、");
let second = String::from("世界!");
let combined = first + &second; // second の前に & が付いていることに注意
println!("{combined}");
// format! のほうが読みやすいことが多い
let name = "Ferris";
let greeting = format!("こんにちは、{name}さん!");
println!("{greeting}");
}
▶ 実際に試してみよう

いつも使うことになるメソッドをいくつか紹介します。この例では、あえてテキストを英語のままにしています。.len() は長さをバイト数で数えますが、日本語の文字は1文字で3バイトになるため、日本語にすると結果が変わってしまうからです。また、大文字・小文字の変換も英字でないと違いがわかりません。

fn main() {
let text = " Hello, Rust! ";
println!("{}", text.trim()); // "Hello, Rust!"(前後の空白を除去)
println!("{}", text.to_uppercase()); // " HELLO, RUST! "
println!("{}", text.to_lowercase()); // " hello, rust! "
println!("{}", text.contains("Rust")); // true
println!("{}", text.trim().len()); // 12(バイト単位の長さ)
println!("{}", text.trim().replace("Rust", "World")); // "Hello, World!"
}
▶ 実際に試してみよう

1文字ずつ順番に処理するには、.chars() を使います。

fn main() {
for c in "abc".chars() {
println!("{c}");
}
}
▶ 実際に試してみよう

誰かがフォームに " rUsT is FUN " と入力しました。これを rust is great に変えてください。余分な空白を取り除き、すべて小文字にして、fun を great に置き換えます。そして、結果とその長さを表示しましょう。ヒント:文字列のメソッドは text.trim().to_lowercase()... のように、次々につなげて呼び出せます。

解答を見る

ここでも、テキストは英語のままにしています。.len() はバイト数を数えるので、日本語にすると結果が変わってしまうからです。

fn main() {
let input = " rUsT is FUN ";
// まず trim、次に小文字にして、(もう小文字になった)"fun" を置き換える
let clean = input.trim().to_lowercase().replace("fun", "great");
println!("{clean}");
println!("{}バイト", clean.len());
}

実行結果:

rust is great
13バイト
▶ 実際に試してみよう

順番が大切です。.to_lowercase() より前に .replace("fun", "great") を呼ぶと、テキストはまだ FUN のままなので、何も置き換わりません。

2. メールアドレスを組み立てる

Section titled “2. メールアドレスを組み立てる”

first = "Ada" と last = "Lovelace" から、[email protected] という String を組み立てて表示してください。それから、@ が含まれているかどうかも表示しましょう。ヒント:format! の {} には、first.to_lowercase() のような式も渡せます。

解答を見る
fn main() {
let first = "Ada";
let last = "Lovelace";
let email = format!("{}.{}@example.com", first.to_lowercase(), last.to_lowercase());
println!("{email}");
println!("正しそう: {}", email.contains('@'));
}

実行結果:

正しそう: true
▶ 実際に試してみよう
  • &str は借用された固定のテキスト、String は所有権を持ち、伸ばせるテキストです。
  • String を伸ばすには、.push_str()(テキスト用)か .push()(1文字用)を使います。
  • 文字列をつなげるときは、+ より format! を使いましょう。わかりやすく、何もムーブしません。
  • よく使うメソッド:.trim()、.to_uppercase()、.contains()、.replace()、.chars()。

理解度チェック

1. 所有権を持ち、実行中に伸ばせる文字列の型はどれですか?

2. 3つ以上の文字列をつなげるとき、このページが + より format! をすすめるのはなぜですか?

3. Rustの文字列に text[0] のようにインデックスでアクセスできないのはなぜですか?

4. greeting.push('!') のように、伸ばせる String に1文字を追加するメソッドはどれですか?

スコア: 0 / 4