【Rust入門】char、&str、String型の違いについて
Rustに入門した中で、文字(列)の扱いについて少し混乱したのでメモ。
C++の復習にもなりますね。
1. 文字(列)型の種類について
-
char
組み込み型(プリミティブ型)。
単一のUnicode文字を表現でき、スタック上に確保される。 -
str
これも組み込み型。
後述のString
型への参照として使用されるので、固定値。別名string slice
(文字列スライス)とも呼ばれる。通常は参照付きの
&str
として使用されがち。
文字列データ自体は別の場所に存在し、それを参照する。
string slice
の先頭のバイトへのポインタとその長さから構成される、&[u8]
型のスライス[1]。 -
String
標準ライブラリで提供される型。文字列データ。実態はVec<u8>型で実装されている。
上記2つと違ってヒープ上に確保され、サイズ変更が可能。
char
と&str
の違いについて
2. シングルクォーテーションかダブルクォーテーションの
どちらで囲んだかによって型推論が変動するので注意。
let a = 'a' // char型
let b = "b" // &str型
また、&str
→char
への変換は以下のように実装する。
let s = "Hello, world!";
for c in s.chars() { // charを取り出すイテレータ.
println!("{}", c);
}
↓
H
e
l
l
o
,
w
o
r
l
d
!
&str
とString
の違いについて
3. 前述のとおり、Stringはヒープで動的に確保された文字列で、strはそれを参照する固定長である。
以下は&str
→String
に変換する例[2]。
let s = "Hello".to_string(); // s: String
また、Stringは所有権を持つ。
4. (余談その1)メモリ上ではどうなってる?
以下のコードを実行した時、内部でどのような事が起こっているか。
let my_str = "hello";
let my_string = String::from(my_str);
L1を実行した時
-
ptr
: 文字列データへのポインタ -
len
: 文字列データの長さ
静的メモリに配置されているため、不変。
staticライフタイムを持つ。
変更の必要がない文字列を宣言する場合はこれで十分。
L2を実行した時
先ほどと異なり、ヒープ上に新しく割り当てられている事がわかる。
-
ptr
: (ヒープ上に割り当てられた)文字列データへのポインタ -
len
: 文字列データの長さ -
capacity
: 現在割り当てられているメモリ量
5. (余談その2)String型は所有権を持つ
組み込み型(プリミティブな値)の値は、所有権を持たない。
これはCopyトレイト
によるもので、ディープコピーの挙動と実質同じと思われる。
1. char型
fn char_example() {
let c1 = 'A';
let c2 = c1; // コピーされる
println!("c1: {}, c2: {}", c1, c2); // 両方使用可能
}
2. &str型
fn str_example() {
let s1 = "Hello";
let s2 = s1; // 参照がコピーされる
println!("s1: {}, s2: {}", s1, s2); // 両方使用可能
}
3. String型
char
やstr
と異なり、所有権を持つ。
fn string_example() {
let s1 = String::from("Hello");
let s2 = s1; // 所有権が移動する
// println!("s1: {}", s1); // コンパイルエラー: s1の所有権はs2に移動している
println!("s2: {}", s2); // s2は使用可能
// String型の借用
let s3 = String::from("World");
let s4 = &s3; // s3を借用
println!("s3: {}, s4: {}", s3, s4); // 両方使用可能
}
6. 所感
結局、メモリ上で何が起こっているかを深堀する事が大事だなぁと感じました🧐
Discussion
from
の引数に渡した&str
の変数が書き換えられるようなことはありません。参照先は元のままのはずです白山様、返信遅くなりました。
ご指摘いただき感謝します。
確認し、文言と図を修正しましたので、また機会があれば見ていただけると幸いです。
コメントありがとうございました。
白山様で指摘された通り
それぞれ異なるアドレスを指します
田中様、返信遅くなりました。
コード添付した上でのご指摘、大変感謝しております。
確認し、文言と図を修正しましたので、もしまた機会があれば見ていただけると幸いです。
まだまだ入門中の身ですので勉強になりました。
コメントありがとうございました。
白山さん、田中さんコメントありがとうございます。
(また、返信遅れてしまい申し訳ございませんでした)
後ほど確認し返信させていただきます。