🦀

100日後にRustをちょっと知ってる人になる: [Day 48]文字列の型: str型とString型

2022/10/17に公開

Day 48 のテーマ

Day 46 では、型を変換するためのトレイトな FromInto の使い方について見てみました。

From トレイトは、ある型に対して、別の型からその型を作る方法を定義できるようにするものでした。
使い方の例として、str に対して String を作る場合の(サンプル](https://zenn.dev/shinyay/articles/hello-rust-day047#from-トレイト)を見てみました。

ところで、この文字列に関する 2 つの型があります。

  • str
  • String

これらをそれぞれどのようなもので、どんな時に使うべきなのかきちんと理解しているかどうか、ということを自分に確認する意味も込めて 2 つの型についてまとめようと思います。

str 型と String 型

まず、それぞれの型で文字列を出力させてみます。

let s_str: &str = "This is str";
let s_string: String = String::from("This is String");

println!("str: {}", s_str);
println!("String: {}", s_string);
str: This is str
Strint: This is String

出力させる文字列の初期化の方法がことなりますが、いずれの型の場合も同じ様に出力することができています。

というわけで、性質の違いを見ていきたいと思います。

str 型

まず str のリファレンスを見てみようと思います。

リファレンスにもかかれているように、str 型は Rust のプリミティブデータ型です。

このリファレンスに 2 つポイントになることが書かれています。

  • 通常は借用した形で &str が使われる
  • 文字列スライスと呼ぶ

なぜ借用

借用とは Rust の中で重要なコンセプトの 1 つで所有権を得ることなく値を参照する仕組みのことでした。
プリミティブ型の str では This is str と定義するとメモリ上に配置先が確保されて割り当てられる文字列のリテラルになります。
&str はそのメモリ上の位置を参照するという呼び出し型なのです。

ここで気をつける必要があるのは、This is str を格納するために確保されたメモリ上の場所のため、This is str を入れるための大きさしか割り当てられていません。しらがって、この &str で定義した文字列に対して文字列の追加など変更ができないのです。

str 型の実体

Immutable (不変) な str 型は、メモリ上のどこかにあるUTF-8のシーケンスです。通常は、そのデータの単なるビューとして文字列スライスとしてUTF-8データへの参照として扱われます。

String 型

次に String のリファレンスを見てみようと思います。

この String 型は str 型と異なりプリミティブ型ではありません。

リファレンスには次のように記載されています:

UTF-8でエンコードされた、成長可能な文字列。
String 型は、文字列の内容に対する所有権を持つ最も一般的な文字列型です。

str との一番の相違点は、String 型として定義した文字列は追加などの変更ができるというところにあります。

let mut s : String = String::from("Hello");
s += ", Rust";  //<-- &str 型の文字列を追加
println!("{}", s);

String 型の文字列に対して、&str 型の文字列を追加することが可能です。

一方で String 型の文字列を直接加えようとするとエラーになります。

let mut s_mut_string1: String = String::from("Hello");
let mut s_mut_string2: String = String::from(", Rust");
s_mut_string1 += s_mut_string2;
   |     s_mut_string1 += s_mut_string2;
   |                      ^^^^^^^^^^^^^
   |                      |
   |                      expected `&str`, found struct `String`
   |                      help: consider borrowing here: `&s_mut_string2`

String 型同士の文字列を結合させる場合であっても、参照を渡すように & をつけて借用しないといけません。

String 型の実体

動的に &str 型の文字列の追加など変更が可能な String 型の実体は、Vec<u8> です。
使い所としては、文字列データを所有したり変更したりする必要がある場合に利用します。

Day 48 のまとめ

Rust には文字列データとして 2 種類の型があることを見てみました。

  • str
  • String

一言に文字列の型といっても、一方はプリミティブ型で、もう片方はことなります。さらに使い方やそれに伴う API なども変わってきます。ただ、使い分けの勘所としては、まずは文字列自体の加工を要するかどうかということを念頭に置いて使い分けをするとよいかなと思います。

GitHubで編集を提案

Discussion