Rust勉強中 - その7 -> bool型とchar型

# 自己紹介
出田 守と申します。
しがない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勉強中 - その6](https://qiita.com/deta-mamoru/items/9c2596a617fdf707ec4f)

# 型
## bool(ブール)型
Rustのbool型はtrueとfalseを持ちます。比較演算の結果をboolとして生成します。

|型|
|---|
|true|
|false|

Rustでは条件式を必要とする文(if文やwhile文など)では**bool値のみ評価**されます。つまり、空文字や0を直接if文に書いてもfalseと評価されません。下記のように試してみましたが、コンパイル時にエラーが出ました。

```Rust:main.rs
fn main() {
    if 0 {
        println!("true");
    } else {
        println!("false");
    }
}
```
```
$ cargo run
   Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
error[E0308]: mismatched types
   --> src\main.rs:142:8
    |
142 |     if 0 {
    |        ^ expected bool, found integer
    |
    = note: expected type `bool`
               found type `{integer}`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `types`.

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

### bool型のキャスト
bool型から整数型へキャストができるようです。

|式|結果|
|---|---|
|true  as u32|1u32|
|false as u32|0u32|
|true  as i32|1i32|
|false as i32|0i32|

ただし、**整数型からbool型へキャストはできません**。以下のようにエラーを吐きます。

```
$ cargo run
   Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
error[E0054]: cannot cast as `bool`
   --> src\main.rs:147:37
    |
147 |     println!("1 as bool = {}{}",    1 as bool, get_type(1 as bool));
    |                                     ^^^^^^^^^ help: compare with zero instead: `1 != 0`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0054`.
error: Could not compile `types`.
```

## char(文字)型
char型は32bit(4byte)でUnicodeの一文字を表します。

### 文字リテラル
char型はシングルクオート(')で文字を囲みます。U+0000~U+007Fの間であれば'\xhh'で書くことができます(hは16進数)。さらに'\u{hhhhhh}としても書くことができます。

|文字リテラル|補足|
|-----------|----|
|'a'|char型のa|
|'\x61'|char型のa|
|'\u{61}'|char型のa|
|'\''|char型の'|
|'\\'|char型の\|
|'\n'|char型のLine feed|
|'\r'|char型のCarriage return|
|'\t'|char型の水平タブ|

### char型のキャスト
char型から整数型へのキャストができます。変換先の型に収まらない場合はその型のサイズに丸められます。
また、u8型からchar型へのキャストができます。

|式|結果|
|---|---|
|'a' as i32 = 97i32(0x61)|
|'\u{100}' as i8|0i8(0b00000000)|
|0x61u8 as char|a|

### char型のメソッド
メソッド例を以下に紹介します。一部のメソッドはOption型を返します。

|式|結果|
|---|---|
|'f'.is_digit(16)|true|
|'f'.is_numeric()|true|
|'f'.to_digit(16)|Some(15)|
|'0xf'.to_digit(16)|Some(15)|
|'f'.to_digit(10)|None|
|std::char::from_u32(0x61)|Some('a')|
|std::char::from_u32(0x7f)|Some('\u{7f}')|
|std::char::from_u32(0x110000)|None|

例によって使ったソースコードを以下に載せておきます。

```Rust:main.rs
...
fn print_bool() {
    println!("\n[print bool examples]");
    println!("true:        \tvalue={}, \ttype={}", true,       get_type(true)); 
    println!("!true:       \tvalue={}, \ttype={}", !true,      get_type(!true)); 
    println!("false:       \tvalue={}, \ttype={}", false,      get_type(false)); 
    println!("!false:      \tvalue={}, \ttype={}", !false,     get_type(!false)); 
    println!("0==0:        \tvalue={}, \ttype={}", 0==0,       get_type(0==0)); 
    println!("0!=0:        \tvalue={}, \ttype={}", 0!=0,       get_type(0!=0)); 
    println!("0==0&&0==0:  \tvalue={}, \ttype={}", 0==0&&0==0, get_type(0==0&&0==0)); 
    println!("0!=0&&0==0:  \tvalue={}, \ttype={}", 0!=0&&0==0, get_type(0!=0&&0==0)); 
    println!("0!=0||0==0:  \tvalue={}, \ttype={}", 0!=0||0==0, get_type(0!=0||0==0)); 
}

fn print_bool_cast() {
    println!("\n[print bool cast]");
    println!("true  as u32 = {}{}", true  as u32, get_type(true  as u32));
    println!("false as u32 = {}{}", false as u32, get_type(false as u32));
    println!("true  as i32 = {}{}", true  as i32, get_type(true  as i32));
    println!("false as i32 = {}{}", false as i32, get_type(false as i32));
    // println!("1 as bool = {}{}",    1 as bool, get_type(1 as bool));
    // println!("0 as bool = {}{}",    0 as bool, get_type(0 as bool));
}

fn print_char_literals() {
    println!("\n[print char literals]");
    println!("'a':     \ttype={}, \tvalue={}", get_type('a'),    'a');
    println!("'\\x61': \ttype={}, \tvalue={}", get_type('\x61'), '\x61');
    println!("'\\u{}61{}': \ttype={}, \tvalue={}", '{', '}', get_type('\u{61}'), '\u{61}');
    println!("'\\'':   \ttype={}, \tvalue={}", get_type('\''),   '\'');
    println!("'\\\\':   \ttype={}, \tvalue={}", get_type('\\'),   '\\');
    println!("'\\n':   \ttype={}, \tvalue={}", get_type('\n'),   '\n');
    println!("'\\r':   \ttype={}, \tvalue={}", get_type('\r'),   '\r');
    println!("'\\t':   \ttype={}, \tvalue={}", get_type('\t'),   '\t');
}

fn print_char_cast() {
    println!("\n[print char cast]");
    println!("'a' as i32 = {}{}(0x{:x})", 'a' as i32, get_type('a' as i32), 'a' as i32);
    println!("'\\u{}100(0b{:08b}){}' as i8  = {}{}(0b{:08b})", '{', 0x100, '}', '\u{100}' as i8, get_type('\u{100}' as i8), '\u{100}' as i8);
    println!("0x61u8 as char = {}", 0x61u8 as char);
    // println!("0x61i32 as char = {}", 0x6132 as char);
}

fn print_char_methods() {
    println!("\n[print char methods]");
    println!("'f'.is_digit(16)              = {}",   '1'.is_digit(16));
    println!("'f'.is_numeric()              = {}",   '1'.is_numeric());
    println!("'f'.to_digit(16)              = {:?}", 'f'.to_digit(16));
    println!("'0xf'.to_digit(16)            = {:?}", 'f'.to_digit(16));
    println!("'f'.to_digit(10)              = {:?}", 'f'.to_digit(10));
    println!("std::char::from_u32(0x61)     = {:?}", std::char::from_u32(0x61));
    println!("std::char::from_u32(0x7f)     = {:?}", std::char::from_u32(0x7f));
    println!("std::char::from_u32(0x110000) = {:?}", std::char::from_u32(0x110000));
}

fn main() {
    // println!(">> Integer type <<");
    // print_int_range();
    // print_int_literals();
    // print_byte_literals();
    // print_int_cast();
    // print_int_methods();
    // println!(">> Floating point type <<");
    // print_float_range();
    // print_float_literals();
    // print_float_cast();
    // print_float_methods();
    println!(">> Bool type <<");
    print_bool();
    print_bool_cast();
    println!(">> Char type <<");
    print_char_literals();
    print_char_cast();
    print_char_methods();
}
```
```
$ cargo run
   Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
    Finished dev [unoptimized + debuginfo] target(s) in 0.62s
     Running `target\debug\types.exe`
>> Bool type <<

[print bool examples]
true:           value=true,     type=bool
!true:          value=false,    type=bool
false:          value=false,    type=bool
!false:         value=true,     type=bool
0==0:           value=true,     type=bool
0!=0:           value=false,    type=bool
0==0&&0==0:     value=true,     type=bool
0!=0&&0==0:     value=false,    type=bool
0!=0||0==0:     value=true,     type=bool

[print bool cast]
true  as u32 = 1u32
false as u32 = 0u32
true  as i32 = 1i32
false as i32 = 0i32
>> Char type <<

[print char literals]
'a':            type=char,      value=a
'\x61':         type=char,      value=a
'\u{61}':       type=char,      value=a
'\'':           type=char,      value='
'\\':           type=char,      value=\
'\n':           type=char,      value=

'\r':           type=char,      value=
'\t':           type=char,      value=

[print char cast]
'a' as i32 = 97i32(0x61)
'\u{100(0b100000000)}' as i8  = 0i8(0b00000000)
0x61u8 as char = a

[print char methods]
'f'.is_digit(16)              = true
'f'.is_numeric()              = true
'f'.to_digit(16)              = Some(15)
'0xf'.to_digit(16)            = Some(15)
'f'.to_digit(10)              = None
std::char::from_u32(0x61)     = Some('a')
std::char::from_u32(0x7f)     = Some('\u{7f}')
std::char::from_u32(0x110000) = None
```

今回はここまで～