Rust勉強中 - その10 -> 文字列型

# 自己紹介
出田 守と申します。
しがないPythonプログラマです。
情報セキュリティに興味があり現在勉強中です。CTFやバグバウンティなどで腕を磨いています。主に低レイヤの技術が好きで、そっちばかり目が行きがちです。

Rustを勉強していくうえで、読んで学び、手を動かし、記録し、楽しく学んでいけたらと思います。

# 環境
新しい言語を学ぶということで、普段使わないWindowsとVimという新しい開発環境で行っています。
OS: Windows10 Home 64bit 1903
CPU: Intel Core i5-3470 @ 3.20GHz
Rust: 1.38.0
RAM: 8.00GB
Editor: Vim 8.1.1
Terminal: PowerShell

# 前回
前回は配列、ベクタ、スライスについて学びました。
[Rust勉強中 - その9](https://qiita.com/deta-mamoru/items/e2262fcde20e8e3f97b9)

# 型
## 文字列型
Rustの文字列型には2つあります。

1. ある文字列の位置を指す`&str`型
2. ヒープメモリ上に確保される文字列を指す`String`型

### バイト文字列
バイト文字列は、u8の列からなるスライスです。先頭にbを付けることで生成できます。

```Rust
fn print_byte_string() {
    println!("\n[print byte string]");
    println!("b\"\\\"byte string\\\"\" = {:?} {:?}", b"\"byte string\"", get_type(b"byte string"));
}
```
```
[print byte string]
b"\"byte string\"" = [34, 98, 121, 116, 101, 32, 115, 116, 114, 105, 110, 103, 34] "&[u8; 11]"
```

### raw string
以前にも説明しましたraw stringです。一部の文字をエスケープをせずにそのまま出力することができます。

```Rust
fn print_raw_string() {
    println!("\n[print raw string]");
    println!("r#\"\"raw string\"\"# = {} {}", r#""raw \nstring""#, get_type(r#"raw \nstring"#));
}
```
```
[print raw string]
r#""raw string""# = "raw \nstring" &str
```

### &str型の生成
&str(「string slice」)は連続したUTF-8テキストへの参照を借用しています。&strは常に有効なUTF-8を指します。また、&strもほかのスライスのように、fat pointerです。つまり、文字列のある位置を指したポインタと要素数を持っています。

```Rust
fn print_string_slice() {
    println!("\n[print string slice]");
    println!("{} {}", "\"string slice\"", get_type("string slice"));
}
```
```
[print string slice]
"string slice" &str
```

### &strの文字へのアクセス
こちらもほかのスライスと同じようなアクセスができます。

```Rust
fn print_string_slice_access() {
    println!("\n[print string slice access]");
    println!("&\"string slice\"[..6] = {} {}", &"string slice"[..6], get_type("string slice"));
    println!("&\"ストリング　スライス\"[..6] = {} {}", &"ストリング　スライス"[..6], get_type("ストリング　スライス"));
    println!("&\"ストリング　スライス\"[..15] = {} {}", &"ストリング　スライス"[..15], get_type("ストリング　スライス"));
}
```
```
[print string slice access]
&"string slice"[..6] = string &str
&"ストリング　スライス"[..6] = スト &str
&"ストリング　スライス"[..15] = ストリング &str
```
**ASCIIは1byteで、UTF-8は複数byteで格納**しています。なので上記のような結果になっています。注意が必要です。

### &strのメソッド
一部のメソッドを載せておきます。

```Rust
fn print_string_slice_methods() {
    println!("\n[print string slice methods]");
    println!("\"string slice\".len() = {}", "string slice".len());
    println!("\"ストリング　スライス\".len() = {}", "ストリング　スライス".len());
    println!("\"ストリング　スライス\".chars() = {:?}", "ストリング　スライス".chars());
    println!("\"ストリング　スライス\".chars().count() = {}", "ストリング　スライス".chars().count());
    println!("\"string slice\".contains(\"sli\") = {}", "string slice".contains("sli"));
    println!("\"string slice\".to_uppercase() = {}", "string slice".to_uppercase());
    println!("\"String Slice\".to_lowercase() = {}", "String Slice".to_lowercase());
    println!("\"\\nstring \\tslice\\n\".trim() = {}", "\nstring slice\n".trim());
}
```
```
[print string slice methods]
"string slice".len() = 12
"ストリング　スライス".len() = 30
"ストリング　スライス".chars() = Chars(['ス', 'ト', 'リ', 'ン', 'グ', '\u{3000}', 'ス', 'ラ', 'イ', 'ス'])
"ストリング　スライス".chars().count() = 10
"string slice".contains("sli") = true
"string slice".to_uppercase() = STRING SLICE
"String Slice".to_lowercase() = string slice
"\nstring \tslice\n".trim() = string slice
```

### Stringの生成方法
&strをスライスへの参照とするなら、Stringはベクタといった位置づけです。
Stringの生成方法は様々にあるようです。

1. String::newとString::with_capacityから生成
2. to_stringメソッドから生成
2. format!マクロから生成
3. concatメソッド, joinメソッドから生成

などなど色々あるようです。

```Rust
fn print_String() {
    println!("\n[print String]");
    println!("String::new()             = {} {}", String::new(), get_type(String::new()));
    println!("String::with_capacity(6)  = {} {}", String::with_capacity(6), get_type(String::with_capacity(6)));
    println!("\"String\".to_string()    = {} {}", "String".to_string(), get_type("String".to_string()));
    println!("format!(\"{}\", \"String\") = {} {}", "{}", format!("{}", "String"), get_type(format!("{}", "String")));
    println!("[\"Str\", \"ing\"].concat() = {} {}", ["Str", "ing"].concat(), get_type(["Str", "ing"].concat()));
}

```
```
[print String]
String::new()             =  alloc::string::String
String::with_capacity(6)  =  alloc::string::String
"String".to_string()    = String alloc::string::String
format!("{}", "String") = String alloc::string::String
["Str", "ing"].concat() = String alloc::string::String
```

### Stringのメソッド
一部メソッドを載せておきます。

```Rust
fn print_String_methods() {
    println!("\n[print String methods]");
    let mut s = String::new();
    println!("s.push('S'); s.push_str(\"tring\") = {}", {s.push('S'); s.push_str("tring"); s});
    println!("\"String\".to_string().len() = {}", "String".to_string().len());
    println!("\"String\".to_string().capacity() = {}", "String".to_string().capacity());
    println!("\"String\".to_string().remove(0) = {}", "String".to_string().remove(0));
}
```
```
[print String methods]
s.push('S'); s.push_str("tring") = String
"String".to_string().len() = 6
"String".to_string().capacity() = 6
"String".to_string().remove(0) = S
```

## 使用したソース

```Rust
...
fn print_byte_string() {
    println!("\n[print byte string]");
    println!("b\"\\\"byte string\\\"\" = {:?} {:?}", b"\"byte string\"", get_type(b"byte string"));
}

fn print_raw_string() {
    println!("\n[print raw string]");
    println!("r#\"\"raw string\"\"# = {} {}", r#""raw \nstring""#, get_type(r#"raw \nstring"#));
}

fn print_string_slice() {
    println!("\n[print string slice]");
    println!("{} {}", "string slice", get_type("string slice"));
}

fn print_string_slice_access() {
    println!("\n[print string slice access]");
    println!("&\"string slice\"[..6] = {} {}", &"string slice"[..6], get_type(&"string slice"[..6]));
    println!("&\"ストリング　スライス\"[..6] = {} {}", &"ストリング　スライス"[..6], get_type(&"ストリング　スライス"[..6]));
    println!("&\"ストリング　スライス\"[..15] = {} {}", &"ストリング　スライス"[..15], get_type(&"ストリング　スライス"[..15]));
}

fn print_string_slice_methods() {
    println!("\n[print string slice methods]");
    println!("\"string slice\".len() = {}", "string slice".len());
    println!("\"ストリング　スライス\".len() = {}", "ストリング　スライス".len());
    println!("\"ストリング　スライス\".chars() = {:?}", "ストリング　スライス".chars());
    println!("\"ストリング　スライス\".chars().count() = {}", "ストリング　スライス".chars().count());
    println!("\"string slice\".contains(\"sli\") = {}", "string slice".contains("sli"));
    println!("\"string slice\".to_uppercase() = {}", "string slice".to_uppercase());
    println!("\"String Slice\".to_lowercase() = {}", "String Slice".to_lowercase());
    println!("\"\\nstring \\tslice\\n\".trim() = {}", "\nstring slice\n".trim());
}

fn print_String() {
    println!("\n[print String]");
    println!("String::new()             = {} {}", String::new(), get_type(String::new()));
    println!("String::with_capacity(6)  = {} {}", String::with_capacity(6), get_type(String::with_capacity(6)));
    println!("\"String\".to_string()    = {} {}", "String".to_string(), get_type("String".to_string()));
    println!("format!(\"{}\", \"String\") = {} {}", "{}", format!("{}", "String"), get_type(format!("{}", "String")));
    println!("[\"Str\", \"ing\"].concat() = {} {}", ["Str", "ing"].concat(), get_type(["Str", "ing"].concat()));
}

fn print_String_methods() {
    println!("\n[print String methods]");
    let mut s = String::new();
    println!("s.push('S'); s.push_str(\"tring\") = {}", {s.push('S'); s.push_str("tring"); s});
    println!("\"String\".to_string().len() = {}", "String".to_string().len());
    println!("\"String\".to_string().capacity() = {}", "String".to_string().capacity());
    println!("\"String\".to_string().remove(0) = {}", "String".to_string().remove(0));
}

fn main() {
    ...
    println!("\n>> String type <<");
    print_byte_string();
    print_raw_string();
    print_string_slice();
    print_string_slice_access();
    print_string_slice_methods();
    print_String();
    print_String_methods();
}
```
```
>> String type <<

[print byte string]
b"\"byte string\"" = [34, 98, 121, 116, 101, 32, 115, 116, 114, 105, 110, 103, 34] "&[u8; 11]"

[print raw string]
r#""raw string""# = "raw \nstring" &str

[print string slice]
string slice &str

[print string slice access]
&"string slice"[..6] = string &str
&"ストリング　スライス"[..6] = スト &str
&"ストリング　スライス"[..15] = ストリング &str

[print string slice methods]
"string slice".len() = 12
"ストリング　スライス".len() = 30
"ストリング　スライス".chars() = Chars(['ス', 'ト', 'リ', 'ン', 'グ', '\u{3000}', 'ス', 'ラ', 'イ', 'ス'])
"ストリング　スライス".chars().count() = 10
"string slice".contains("sli") = true
"string slice".to_uppercase() = STRING SLICE
"String Slice".to_lowercase() = string slice
"\nstring \tslice\n".trim() = string slice

[print String]
String::new()             =  alloc::string::String
String::with_capacity(6)  =  alloc::string::String
"String".to_string()    = String alloc::string::String
format!("{}", "String") = String alloc::string::String
["Str", "ing"].concat() = String alloc::string::String

[print String methods]
s.push('S'); s.push_str("tring") = String
"String".to_string().len() = 6
"String".to_string().capacity() = 6
"String".to_string().remove(0) = S
```

今回はここまで。
ここまでで一応基本的な型は終わりです。