Rust

Rustのfor文でのループカウンタ変数の型合わせ

Rust

[PR]当サイトはアフィリエイト広告を利用しています。

そろそろパソコンを新調したいというときはこちらもどうぞ。安さと機能のバランスが取れたPCを紹介しています。

プログラミングおすすめPC

マウスコンピューターのセールもチェックすると掘り出し物が見つかるかも。

はじめに

今回はRustの型合わせに関する内容。

Rustは型に厳密なので、とりあえず書いてみて、エラーが出たら型合わせするようなやり方でコードを書いています。

今回はfor文のiが時と場合によってうまく動いたりそうでなかったりするという現象についてです。

以前このブログで扱った「VLOOKUP関数っぽい処理をVBAで書いてみる(料金表の検索)」の例題を扱って、それをRustで書いてみるという内容になります。

今回の例題

次のような料金とします。

人数平日料金(円)税別休日料金(円)税別
160007000
21100013000
31800021000
42400028000
53200040000

ここから人数と平日か休日かを入力することで金額を税込みで出力することにします。

エラー1

Pythonの感覚で次のようなコードを書きました。

fn main(){
    println!("人数を入力");
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    let num: i32 = line.trim().parse().ok().unwrap();
    println!("平日か休日か");
    let mut line2 = String::new();
    std::io::stdin().read_line(&mut line2).ok();
    let h_or_w = line2.trim().to_string();
    let weekday = [6000,11000,18000,24000,32000];
    let holiday = [7000,13000,21000,28000,40000];
    for i in 0..5 {
        if h_or_w == "平日"{ 
            if num == (i + 1) {
                let temp = weekday[i] as f32; 
                println!("料金:{}",temp * 1.1);
            }
        }
        if h_or_w == "休日" { 
            if num == (i + 1) {
                let temp = holiday[i] as f32; 
                println!("料金:{}",temp * 1.1);
            }
        }
    }
}

すると

let temp = weekday[i] as f32;

| ^ slice indices are of type `usize` or ranges of `usize`

このようなエラーが出ます。

要するに配列weekdayのインデックス指定の変数がusizeではないからダメだという話。

エラー2

そこでfor文の0..5の部分を次のように修正。

    for i in 0..(5 as usize) {
        if h_or_w == "平日"{
            if num == (i + 1) {
                let temp = weekday[i] as f32; 
                println!("料金:{}",temp * 1.1);
            }
        }
        if h_or_w == "休日" {
            if num == (i + 1) {
                let temp = holiday[i] as f32; 
                println!("料金:{}",temp * 1.1);
            }
        }
    }

すると次のようなエラーが。

if num == (i + 1) {

| ^^^^^^^ expected `i32`, found `usize`

これを

if num == ((i + 1)).try_into().unwrap() {

とするようにコンパイラから指示されます。

しかしながらtry_into().unwrap()を書いてもエラーは直りません。

iをusizeにしたから今度は(i + 1)の部分がi32型ではないのでエラーという堂々巡り。

どうしたものか。

完成版

次のように、iを型変換して別の変数に格納することで解決。

fn main(){
    println!("人数を入力");
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    let num: i32 = line.trim().parse().ok().unwrap();
    println!("平日か休日か");
    let mut line2 = String::new();
    std::io::stdin().read_line(&mut line2).ok();
    let h_or_w = line2.trim().to_string();
    let weekday = [6000,11000,18000,24000,32000];
    let holiday = [7000,13000,21000,28000,40000];
    for i in 0..(5 as usize) {
        if h_or_w == "平日"{
            let i2 = i as i32; 
            if num == (i2 + 1) {
                let temp = weekday[i] as f32; 
                println!("料金:{}",temp * 1.1);
            }
        }
        if h_or_w == "休日" {
            let i2 = i as i32; 
            if num == (i2 + 1) {
                let temp = holiday[i] as f32; 
                println!("料金:{}",temp * 1.1);
            }
        }
    }
}

要するに

let i2 = i as i32;

if num == (i2 + 1) {

このように、iをi2というi32型の変数にキャストしてi2をiのように使うという話。

これでコンパイルに成功しました。

まとめ

今回はfor文での型合わせについて書きました。

型に厳密だからエラーも少ない。

その代わり、コンパイル時点でいろいろな変数の型を合わせる作業が必要。

慣れが必要そうですね。