rust学習-文字列Strings

8209 ワード

Stringとは?
Rustはコア言語に1つの文字列タイプ、すなわち文字列スライスstrしかなく、通常は借用形式&strで見られる.
StringタイプはRustの標準ライブラリで提供され、コア言語として符号化されるのではなく、拡張可能、可変可能、保有可能なUTF-8形式で符号化された文字列タイプである.Rustで「strings」を参照する場合、通常はStringと文字列スライス&strタイプを指しますが、stringsはこの2つのタイプだけではありません.しかし、2つのタイプはRustの標準ライブラリで最も多く使用され、Stringと文字列スライス&strはUTF-8で符号化されています.
Rustの標準ライブラリには、OsString、OsStr、CString、CStrなど、多くの他の文字列タイプも含まれています.図書館パッケージ(Library crates)は、文字列データを格納するためのオプションをより多く提供します.なぜこれらの名前はどのようにStringまたはStrで終わるのですか?Stringやstrタイプのように、所有と借用の変形を指すからです.たとえば、これらの文字列タイプは、異なる符号化でテキストを格納したり、メモリに異なる方法で表すことができます.
新しい文字列を作成
fn main() {
    let mut s = String::new(); // s, s。
}

通常、文字列の先頭に初期データを使用します.そのため、to_を使用します.stringメソッドは、文字列文字のようにDisplayフィーチャーを実装する任意のタイプで使用できます.次の2つの効果がまったく同じ例を示します.
// 。
fn main() {
    let data = " ";

    let s = data.to_string();

    //  :
    let s = " ".to_string();
} 

関数String::fromを使用して文字列文字から文字列を作成することもできます.効果はto_の使用に等しいstring:
fn main() {
    let s = String::from(" ");
}

文字列はUTF-8で符号化されていると考えられているので、以下に示すように、正しく符号化されたデータを含めることができます.
fn main() {
    let hello = String::from(" ");
    let hello = String::from("Hello");
    let hello = String::from("السلام عليكم");
    let hello = String::from("Dobrý den");
    let hello = String::from("שָׁלוֹם");
    let hello = String::from("नमस्ते");
    let hello = String::from("こんにちは");
    let hello = String::from("안녕하세요");
    let hello = String::from("Olá");
    let hello = String::from("Здравствуйте");
    let hello = String::from("Hola");
}

文字列の更新
より多くのデータを文字列に押し込むと、文字列のサイズが増加し、Vecの内容のように内容が変化します.また、+演算子やフォーマットを簡単に使用できます.
push_の使用strとpushを文字列に添付
fn main() {
    let mut s1 = String::from("foo");
    let s2 = "bar";
    s1.push_str(s2);
    println!("s2 is {}", s2);
}
// :s2 is bar。 push_str 

Pushメソッドは、単一の文字をパラメータとしてStringに追加します.次の例では、pushメソッドを使用してStringにアルファベットlを追加するコードを示します.
fn main() {
    let mut s = String::from("lo");
    s.push('l');
}

注意pushメソッドを使用する場合は、単一引用符を使用する必要があります.二重引用符を使用するとエラーが発生します.
|
4 | s1.push("l");
|             ^^^ expected `char`, found `&str`

+演算子または形式と直列に接続します.通常、マクロは2つの既存の文字列を結合する必要があります.次のように+演算子を使用します.
fn main() {
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2; //  s1 , 
    println!("s1 + &s2 = {}", s3);
}

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.60s
     Running `target\debug\cargo_learn.exe`
s1 + &s2 = Hello, world!

+演算子はaddメソッドを使用し、次のように署名します.fn add(self, s: &str) -> String {
上記の例では、+記号演算を使用して新しい文字列を取得できますが、プラス記号が多い場合は何が起こっているのか分かりにくいことがわかります.より複雑な文字列の組み合わせでは、format!マクロを使用できます.
fn main() {
    let s1 = String::from(" ");
    let s2 = String::from(" ");
    let s3 = String::from(" !");

    let s = format!("{}-{}-{}", s1, s2, s3);

    println!("{}", s1);
    println!("{}", s)
}
D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.59s
     Running `target\debug\cargo_learn.exe`
 
 - - !

使用を見ることができますformat!は、借用変数を参照するだけで、変数の所有権は取得されません.
文字列にインデックスするには、jsでjsのクリップを取得するようにrustで使用できますか.たとえば、次のようにします.
fn main() {
    let s1 = String::from("hello");
    let h = s1[0];
    println!("{}", h);
}

答えはだめです.
D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
error[E0277]: the type `std::string::String` cannot be indexed by `{integer}`
 --> src\main.rs:3:13
  |
3 |     let h = s1[0];
  |             ^^^^^ `std::string::String` cannot be indexed by `{integer}`
  |
  = help: the trait `std::ops::Index` is not implemented for `std::string::String`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `cargo_learn`.

To learn more, run the command again with --verbose.

どうしてできないの?まずRustがメモリに文字列を格納する方法を見てみましょう.
内部代表文字列はVecのパッケージです.まず、正しく符号化されたUTF-8の文字列の例を見てみましょう.let hello = String::from("Hola");この場合、lenは4になります.これは、文字列「Hola」を格納するベクトルの長さが4バイトであることを意味します.UTF-8でエンコードする場合、アルファベットごとに1バイトを占有します.でももしそうなら?let hello = String::from("Здравствуйте"); //( , Ze , 3。)
文字列の長さを尋ねると、12と言うかもしれません.しかし、Rustの答えは24:これはUTF-8で符号化されています」Здравствуйте”この文字列内のUnicodeスカラー値ごとに2バイトの記憶領域が使用されるため、必要なバイト数.
したがって、文字列バイトのインデックスは、常に有効なUnicodeスカラー値に関連付けられているわけではありません.そこでプレゼンテーションのために、以下の無効なRustコードを見てみましょう.
let hello = "Здравствуйте";
let answer = &hello[0];

答えの価値は何ですか?はずですЗ,最初のアルファベットですか?UTF-8で符号化する場合、Зの最初のバイトは208で、2番目のバイトは151なので、答えは実際には208であるべきだが、208自体は有効な文字ではない.ユーザがこの文字列の最初のアルファベットを入力するように要求した場合、戻り208はユーザが望んでいない可能性がある.ただし、これはRustがバイトインデックス0を持つ唯一のデータです.文字列にラテン文字のみが含まれている場合でも、ユーザは通常、バイト値を返すことを望んでいない.&「hello」[0]がバイト値を返す有効なコードである場合、hではなく104を返す.予期せぬ値が返され、すぐに発見されない可能性のあるエラーを回避するために、Rustはコードを完全にコンパイルせず、開発プロセスの早期の誤解を回避しました.
バイト(bytes)とスカラー値(scalar values)とフォントクラスタ(grapheme clusters)!
UTF-8のもう一つの点は、Rustの観点から見ると、実際には文字列:バイト、スカラー値、ワードクラスタ(アルファベットに最も近いもの)を表示する3つの関連方法があります.
梵文スクリプトで記述された北インド語の単語「
[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,224, 165, 135]

それは18バイトで、これはコンピュータが最終的にこのデータを格納する方法です.Unicodeスカラー値(Rustのcharタイプ)と見なす場合、これらのバイトは以下のように示されます.['न', 'म', 'स', '्', 'त', 'े']ここには6つのchar値がありますが、4番目と6番目はアルファベットではありません.これらは変音記号で、それら自体は意味がありません.最後に、それらをフォントクラスタと見なすと、ヒンディー語の単語を構成する4つのアルファベットが得られます.["न", "म", "स्", "ते"]Rustは、コンピュータに格納された元の文字列データを解釈するための異なる方法を提供し、データが使用する言語に関係なく、プログラムごとに必要な解釈を選択することができる.RustがStringにインデックスして文字を取得することを許可しない最後の理由は、インデックス操作に常に一定の時間(O(1))が必要であるためである.しかし、Stringではパフォーマンスが保証されません.Rustは、有効な文字がどれだけあるかを決定するために、すべてのコンテンツを最初から最後まで巡回する必要があります.
スライス文字列が文字列をインデックス化するのは、通常、文字列インデックス操作の戻りタイプがバイト値、文字、フォントクラスタ、文字列スライスであることが分からないため、悪い考えです.したがって、Rustは、文字列スライスを作成するためにインデックスを使用する必要があるかどうかをより具体的に説明する必要がある.インデックスをより具体的に示し、単一の数値を持つ[]ではなく文字列スライスを使用することを示すために、[]を範囲と組み合わせて使用して、特定のバイトを含む文字列スライスを作成できます.
#![allow(unused_variables)]
fn main() {
    let hello = "Здравствуйте";

    let s = &hello[0..4];
    println!("{}",s);
}
D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.55s
     Running `target\debug\cargo_learn.exe`
Зд

文字列を巡る方法幸いなことに、文字列の要素には他の方法でアクセスできます.
単一のUnicodeスカラー値を操作する必要がある場合は、charsメソッドを使用するのが最善です.「検索」でcharを使用すると、charタイプの6つの値が分離され、返されます.結果を巡回して各要素にアクセスできます.
#![allow(unused_variables)]
fn main() {
    for c in "नमस्ते".chars() {
        println!("{}", c);
    }
}

D:\learn\cargo_learn>cargo run
   Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
     Running `target\debug\cargo_learn.exe`
न
म
स
्
त
े

bytesメソッドは、元のバイトごとに返されます.これは、私たちの初心に適している可能性があります.
#![allow(unused_variables)]
fn main() {
    for b in "नमस्ते".bytes() {
        println!("{}", b);
    }
}

このコードは、この文字列を構成する18バイトを印刷します.
224
164
// --snip--
165
135

有効なUnicodeスカラー値は、1バイト以上で構成される場合があります.
文字列からワードクラスタを取得するのは複雑なため、rust標準ライブラリではこの機能は提供されません.でも私たちはcratesでioでの取得使用
文字列はそんなに簡単ではありません
要するに文字列は複雑です.Rustは、StringデータをすべてのRustプログラムのデフォルトの動作として正しく処理することを選択します.これは、UTF-8データの処理にもっと力を入れなければならないことを意味します.このトレードオフはより多くの文字列の複雑さをもたらしますが、開発ライフサイクルの後半に非ASCII文字に関するエラーを処理しなければならないことを防止します.