Rust dojo第15回を開催した

 第15回です。

前回はこちら。

kdnakt.hatenablog.com

 

 

[第15回の様子]

2021/10/20に第15回を開催した。

 

内容としてはRust By Example 日本語版の「4.4. 値のフリーズ」、「5. Types」、「5.1. 型キャスティング」に取り組んだ。

 

参加者はちょっと戻ってきて、全部で8人。

 

Slackでの書き込みは相変わらず少なめだが、dojo開催中の会話が少し増えてきてる気がする。

 

[学んだこと]

fn main() {
    let mut _mutable_integer = 7i32;
    {
        let _mutable_integer = _mutable_integer;
        _mutable_integer = 50;
    }
}

// コンパイルエラー
   Compiling playground v0.0.1 (/playground)
error[E0384]: cannot assign twice to immutable variable `_mutable_integer`
  --> src/main.rs:10:9
   |
6  |         let _mutable_integer = _mutable_integer;
   |             ----------------
   |             |
   |             first assignment to `_mutable_integer`
   |             help: consider making this binding mutable: `mut _mutable_integer`
...
10 |         _mutable_integer = 50;
   |         ^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
  • これまで手を動かしてきたところ当たり前な感じがする...Kotlin/Nativeで出てきたフリーズの概念ともちょっと違う気がするし、なぜ別の章立てがされているのか謎。
  • 5. Types
  • プリミティブ型とユーザー定義型をいろいろ扱いますよ、と。
  • 5.1. 型キャスティング
  • 型を変換(キャスティング)すると、数字の場合けたあふれが心配...と思っていたら、Rustは自動で警告を出してくれるらしい
  • 警告を無視する場合には、以下のコードで警告を抑止できる
// オーバーフローを起こすようなキャスティングによる警告を無視する。
#![allow(overflowing_literals)]
fn main() {
    println!("1000 as a u8 is : {}", 1000 as u8);
}

// コンパイルエラー
   |
35 |     println!("1000 as a u8 is : {}", 1000 as u8);
   |                                      ^^^^
   |
   = note: `#[deny(overflowing_literals)]` on by default
   = note: the literal `1000` does not fit into the type `u8` whose range is `0..=255`

error: literal out of range for `i8`
  • 型の暗黙的な変換はできない
fn main() {
    let decimal = 65.4321_f32;
    let integer: u8 = decimal;
}

// 以下のコンパイルエラー
   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:10:23
   |
10 |     let integer: u8 = decimal;
   |                  --   ^^^^^^^ expected `u8`, found `f32`
   |                  |
   |                  expected due to this
  • 型変換は明示的にas u8などのように行う必要がある
fn main() {
    let decimal = 65.4321_f32;

    let integer = decimal as u8;
    let character = integer as char;

    println!("Casting: {} -> {} -> {}", decimal, integer, character);
    // Casting: 65.4321 -> 65 -> A
}
  • u16をu8にキャストすると以下のようになる
fn main() {
    println!("1000 is: {}\n[{:b}]", 1000, 1000); // デフォルトはi32
    // 1000 is: 1000
    // [1111101000]
    println!("1000 as a u16 is: {}\n[{:b}]", 1000 as u16, 1000 as u16);
    // 1000 as a u16 is: 1000
    // [1111101000]
    println!("1000 as a u8 is : {}\n[{:b}]", 1000 as u8, 1000 as u8);
    // 1000 as a u8 is : 232 (1000-256-256-256=232)
    // [11101000] (8ビットしかないので上位ビットが落ちる)
    println!("1000 mod 256 is : {} [{:b}]", 1000 % 256, 1000 % 256);
    // 1000 mod 256 is : 232
    
    println!("  -1 as a i8 is : {}\n[{:b}]", -1i8, -1i8);
    // -1 as a i8 is : -1
    // [11111111]
    println!("  -1 as a u8 is : {}\n[{:b}]", (-1i8) as u8, (-1i8) as u8);
    // -1 as a u8 is : 255 (-1 + 256 = 255)
    // [11111111]
}
  • 符号付きの型にキャストする場合、以下の2つを行った結果と等しくなる
    1. 対応する符号なしの型にキャストする。
    2. 2の補数(two's complement)をとる
fn main() {
    // 128をu8にキャストすると128となる。128の8ビットにおける補数は -128
    println!(" 128 as a i8 is : {} [{:b}]", 128 as i8, 128 as i8);
    // 128 as a i8 is : -128 [10000000]
    
    // 1000 as u8 -> 232
    println!("1000 as a u8 is : {} [{:b}]", 1000 as u8, 1000 as u8);
    // 1000 as a u8 is : 232 [11101000]
    
    // 232の8ビットにおける補数は -24
    println!(" 232 as a i8 is : {} [{:b}]", 232 as i8, 232 as i8);
    //  232 as a i8 is : -24 [11101000]
    
    // よって以下もおなじ結果
    println!("1000 as a i8 is : {} [{:b}]", 1000 as i8, 1000 as i8);
    // 1000 as a i8 is : -24 [11101000]
}
  • この符号付き整数型を2の補数とするという定義はC言語では未定義らしい。
  • C++C++20でようやく定義されたらしい。言語によってこの辺も違うんだな。

cpprefjp.github.io

 

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。

久しぶりに2の補数とか出てくると脳みそが疲れる...。

 

今週のプルリクエストはこちら。

github.com