Nao000のぶろぐ

蝶を追っている少年になりたい

Rust 整数型でバリアント未指定の場合必ずi32が割り当てられるわけではないということ

コンパイル時に型が自動で決まるから

結論から言うとコンパイル時に型が自動で決まるからです。この記事を書いていると「まぁそういう仕様だからなあ」となってしまったのですが、折角書いたのでそのまま記事投稿します。何を不思議に思ったかで言うと以下の状況です。整数型でバリアント指定しない場合は基本的には i32 になるけど異なる場合もあるんだなという状況です。

        let a = 100i32;
        let b = 50u32;
        // もちろんエラーになる
        let c = a + b;

        let a = 100;
        let b = 50u32;
        // ↓↓エラーにならない
        let c = a + b;
        // 変数a のバリアントは u32 になるみたい

バリアントとは

i32, i16 とかのサイズ指定です。日本語版のThe Rust Programming Language にてバリアントとして表記されていましたのでそのまま表記します

異なるバリアントの整数型を混ぜたてエラーになる場合

変数aは符号なし8ビットで、変数bは符号なし32ビットの数値です。これを実行するとコンパイルエラーによって失敗します。

ソースコード

    fn main() {
        let a = 100u8;
        let b = 50u32;
        let c = a + b;
        println!("{}", c);
    }

実行結果

    Compiling playground v0.0.1 (/playground)
    error[E0308]: mismatched types
     --> src/main.rs:4:17
      |
    4 |     let c = a + b;
      |                 ^ expected `u8`, found `u32`

    error[E0277]: cannot add `u32` to `u8`
     --> src/main.rs:4:15
      |
    4 |     let c = a + b;
      |               ^ no implementation for `u8 + u32`
      |
      = help: the trait `std::ops::Add<u32>` is not implemented for `u8`

    error: aborting due to 2 previous errors

    Some errors have detailed explanations: E0277, E0308.
    For more information about an error, try `rustc --explain E0277`.
    error: could not compile `playground`.

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

as キーワードを使うことでバリアント変換

異なるバリアントの整数型を混ぜた加算をする場合 as キーワードを使うことで変換することが可能になるようです。

ソースコード

    fn main() {
        let a = 100u8;
        let b = 50u32;
        let c = a as u32 + b;
        println!("{}", c);
    }

実行結果

150

バリアント指定がない場合はi32になる

Rustの整数型でバリアント指定が無い場合は符号付き32ビットの i32 になるようです。

では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、 Rustの基準型は一般的にいい選択肢になります。整数型の基準はi32型です: 64ビットシステム上でも、 この型が普通最速になります。

引用元: https://doc.rust-jp.rs/book/second-edition/ch03-02-data-types.html

バリアント指定無し整数とバリアント指定有り整数を混ぜると?

コンパイルエラーにはならないようです。以下の引用にある通りコンパイル時にはバリアント指定されている変数bに合わせたバリアントが変数aに設定されるのでしょう。てっきり i32 のバリアントが設定されるかと思いましたが、使用方法に基づいたバリアントが指定されるようです。

Rustは静的型付き言語であることを弁えておいてください。つまり、 コンパイル時に全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 使用したい型を推論してくれます。

引用元: https://doc.rust-jp.rs/book/second-edition/ch03-02-data-types.html

ソースコード

    fn main() {
        let a = 100;
        let b = 50u32;
        let c = a + b;
        println!("{}", c);
    }

実行結果

150

参考資料