回答:
String動的ヒープ文字列型Vecです。たとえば、文字列データを所有または変更する必要がある場合に使用します。
strメモリ内の動的な長さのUTF-8バイトの不変の1シーケンスです。サイズは不明なので、ポインタの後ろでしか処理できません。これは、str最も一般的には2が次のように表示されることを意味し&strます。通常は「文字列スライス」または単に「スライス」と呼ばれる一部のUTF-8データへの参照。スライスは一部のデータのビューであり、そのデータはどこにでも配置できます。
"foo"は、文字列リテラルは&'static strです。データは実行可能ファイルにハードコードされ、プログラムの実行時にメモリに読み込まれます。String:Stringへのデリファレンス&strビューのStringのデータを。スタック上:たとえば、次はスタックに割り当てられたバイト配列を作成し、そのデータのビューをとして&str取得します。
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
要約すると、String所有する文字列データが必要な場合(文字列を他のスレッドに渡す、または実行時に作成するなど)と&str、文字列のビューのみが必要な場合に使用します。
これは、vector Vec<T>とslice &[T]の関係と同じであり、一般的な型の値Tによる参照と参照による関係に似てい&Tます。
1 A strは固定長です。末尾を超えてバイトを書き込んだり、末尾の無効なバイトを残したりすることはできません。UTF-8は可変幅エンコーディングstrなので、多くの場合、これによりすべてのが実質的に不変になります。一般に、ミューテーションでは、以前よりも多いまたは少ないバイト数を書き込む必要があります(たとえば、a(1バイト)をä(2+バイト)で置き換えると、にスペースを増やす必要がありますstr)。のように&strインプレースを変更できる特定のメソッドがあり、ほとんどがASCII文字だけを処理するものですmake_ascii_uppercase。
2 動的にサイズ設定される型ではRc<str>、Rust 1.2以降の参照カウントされたUTF-8バイトのシーケンスなどが可能です。Rust 1.21では、これらのタイプを簡単に作成できます。
[u8; N]。
Rc<str>なりましたArc<str>。
私はC ++のバックグラウンドを持ってStringおり&str、C ++の用語で考えることは非常に便利だと思いました。
Stringはのようなものstd::stringです。それはメモリを所有し、メモリを管理するという汚い仕事をします。&strはchar*(しかし少し洗練された)のようなものです。これは、の内容へのポインタを取得できるのと同じ方法で、チャンクの先頭を示しますstd::string。どちらかが消えるのでしょうか?そうは思わない。彼らは2つの目的を果たします:
Stringバッファを保持し、使用することは非常に実用的です。&str軽量で、文字列を「調べる」ために使用する必要があります。新しいメモリを割り当てる必要なく、チャンクを検索、分割、解析、さらには置き換えることができます。
&strString文字列リテラルを指すことができるので、の内部を見ることができます。次のコードは、リテラル文字列をStringマネージメモリにコピーする必要があります。
let a: String = "hello rust".into();
次のコードでは、コピーなしでリテラル自体を使用できます(ただし、読み取り専用です)。
let a: &str = "hello rust";
それらは実際には完全に異なります。まず、a strは型レベルのものにすぎません。いわゆる動的サイズ型(DST)であるため、型レベルでしか推論できません。サイズstr取りは、コンパイル時に知られており、実行時の情報に依存することはできません-それは、変数に格納することはできませんコンパイラは、各変数のサイズが何であるかをコンパイル時に知っておく必要があるため。A strは概念的には単なるu8バイトの行であり、有効なUTF-8を形成することが保証されています。行の大きさはどれくらいですか?実行時まで誰も知らないため、変数に格納することはできません。
おもしろいことは、実行時にa &strや他のstrlike へのポインタBox<str> が存在することです。これは、いわゆる「ファットポインタ」です。これは、追加情報(この場合は指しているもののサイズ)を含むポインターなので、2倍の大きさになります。実際、a &strはa に非常に近くなっていますString(ただしaには近くありません&String)。A &strは2つの単語です。aの最初のバイトへの1つのポインタと、theのバイトstr数を示す別の数値str。
言われていることに反して、a strは不変である必要はありません。を&mut strへの排他的ポインタとして取得できる場合、それを変更できます。変更するstrすべての安全な関数は、UTF-8制約が守られていることを保証します。違反している場合、ライブラリはこの制約がtrueであり、チェックしません。
だから何Stringですか?それは3つの単語です。2つはforと同じです&strがstr、ヒープ上のバッファの容量である3番目のワードが追加されます。ヒープは常にヒープ上にあり(a strはヒープ上にあるとは限りません)、いっぱいになる前に管理され、再割り当てする必要があります。彼らが言うように、String基本的にはを所有しstrています。それはそれを制御し、サイズを変更し、適切と思われるときに再割り当てすることができます。つまり、a Stringはに近い&strということstrです。
もう1つはBox<str>です。これはまた、所有しているstrと、そのランタイム表現は同じである&strが、それはまた、所有しているstrとは異なり&strますが、それはそれのサイズを変更することはできません、それはその能力を知らないので、とても基本的にBox<str>、固定長として見ることができますStringすることができます(サイズを変更することはできませんStringサイズを変更する場合は、常にに変換してください)。
UTF-8制約がなく[T]、非常に類似した関係が存在しVec<T>ます。これには、サイズが動的でない任意のタイプを保持できます。
str型レベルでのの使用は、主にで汎用的な抽象化を作成すること&strです。特性を簡単に記述できるように、型レベルに存在します。理論的にstrは、型として存在する必要はありませんでしたが、それだけ&strでは、汎用になり得る多くの追加コードを記述する必要があります。
&strStringコピーせずにaの複数の異なる部分文字列を持つことができるので非常に便利です。前述のように、a String はstrそれが管理するヒープ上でを所有し、aの部分文字列をString新規Stringでのみ作成できる場合は、コピーする必要があります。たとえば、文字列をスライスできます。
let string: String = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];
str同じ文字列の2つの異なる部分文字列があります。ヒープ上stringの実際のフルstrバッファーを所有するものであり、&str部分文字列はヒープ上のそのバッファーへの単なるファットポインターです。
std::Stringは単にのベクトルですu8。ソースコードでその定義を見つけることができます。ヒープに割り当てられ、拡張可能です。
#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
}
strプリミティブ型であり、string sliceとも呼ばれます。文字列スライスのサイズは固定されています。のようなリテラル文字列にlet test = "hello world"は&'static str型があります。testこの静的に割り当てられた文字列への参照です。
&strたとえば、変更することはできません
let mut word = "hello world";
word[0] = 's';
word.push('\n');
str変更可能なスライスがあります&mut str。例えば:
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
let mut s = "Per Martin-Löf".to_string();
{
let (first, last) = s.split_at_mut(3);
first.make_ascii_uppercase();
assert_eq!("PER", first);
assert_eq!(" Martin-Löf", last);
}
assert_eq!("PER Martin-Löf", s);
ただし、UTF-8を少し変更するとバイト長が変更される可能性があり、スライスはその参照先を再割り当てできません。
簡単に言えば、Stringはデータ型がヒープに格納されている(と同じようにVec)ので、その場所にアクセスできます。
&strスライスタイプです。つまりString、ヒープ内のすでに存在する場所への参照にすぎません。
&str実行時に割り当てを行いません。したがって、メモリ上の理由から、&strover を使用できますString。ただし、使用&strする場合は、明示的なライフタイムを処理する必要がある場合があることに注意してください。
strがviewすでにStringヒープに存在しているということでした。
C#およびJavaのユーザー向け:
String===StringBuilder &str ===(不変)文字列私&strは、文字列のビューとして考えるのが好きです。たとえば、Java / C#のインターンされた文字列は変更できず、新しい文字列を作成するだけです。
ここにすばやく簡単な説明があります。
String-拡張可能で所有可能なヒープ割り当てデータ構造。強制的に&str。
str-(現在、Rustの進化に伴い)ヒープ上またはバイナリ内にある可変の固定長文字列です。strなどの文字列スライスビューを介して、借りた型としてのみ対話でき&strます。
使用上の考慮事項:
好むStringあなたは、文字列を所有しているか、または変異させたい場合-など、別のスレッドに文字列を渡すと
&str文字列の読み取り専用ビューが必要な場合に優先します。
&str二つの成分で構成されています。いくつかのバイトへのポインタ、および長さを。」