Rust初心者がRustを勉強してみた備忘録 その02

# 04. 値の演算および変数の取り扱い
計算、変数の取り扱いを学んでいきます。

Rustでは、変数の取り扱いがすごく難しいので、まずは簡単なものから学んでいきます。

## 04.01. 数値の演算
練習をするためのプロジェクトを作成します。
```
$ cargo new calc_numeric
```

数値の演算で使える演算子は、次のとおりです。
 - 足し算: +
 - 引き算: -
 - 掛け算: *
 - 割り算: /
 - 剰余算: %

使い方を、コードを見ながら習得していきましょう。
```main.rs
fn main() {
    //足し算、引き算
    let price_a = 100;
    let price_b = 200;
    let price_c = 123;
    let discount= 150;
    let summery = price_a + price_b + price_c - discount;

    println!("商品A: {}, 商品B: {}, 商品C: {}, 値引き: {}, 合計 : {}",
            price_a, price_b, price_c, discount, summery);

    //掛け算
    let radius = 5.0;
    let area = radius * radius * 3.141592;

    println!("半径 {} の円の面積は: {} ", radius, area);

    //割り算
    let summery_izakaya_integer = 13423;
    let number_of_person_integer = 6;
    let price_one_person_integer = summery_izakaya_integer / number_of_person_integer;

    println!("飲み代の合計: {},人数は: {}, 一人あたり: {}", 
         summery_izakaya_integer, number_of_person_integer, price_one_person_integer);

    let summery_izakaya_float = 13423.0;
    let number_of_person_float = 6.0;
    let price_one_person_float = summery_izakaya_float / number_of_person_float;

    println!("飲み代の合計: {},人数は: {}, 一人あたり: {}", 
        summery_izakaya_float, number_of_person_float, price_one_person_float);

    //剰余算
    let goukei_kingaku = 9843;
    let ninzu = 5;
    let hasuu = goukei_kingaku % 500;
    let hitori_atari = (goukei_kingaku - hasuu) / ninzu;

    println!("飲み代の合計: {},人数は: {}, 一人あたり: {}, 端数: {}", 
    goukei_kingaku, ninzu, hitori_atari, hasuu);

}

```


●解説

・足し算・引き算
足し算、引き算は、それぞれ + - の演算子を使います。
```
    let price_a = 100;
    let price_b = 200;
    let price_c = 123;
    let discount= 150;
    let summery = price_a + price_b + price_c - discount;
```

出力
```
商品A: 100, 商品B: 200, 商品C: 123, 値引き: 150, 合計 : 273
```

・掛け算
掛け算は * の記号を使います。
```
    //掛け算
    let radius = 5.0;
    let area = radius * radius * 3.141592;

    println!("半径 {} の円の面積は: {} 。", radius, area);
```
出力
```
半径 5 の円の面積は: 78.5398
```

・割り算
割り算は / の記号を使います。なお、整数での割り算はあまりは切り捨てになります。
```
    //割り算
    let summery_izakaya_integer = 13423;
    let number_of_person_integer = 6;
    let price_one_person_integer = summery_izakaya_integer / number_of_person_integer;

    println!("飲み台の合計: {},人数は: {}, 一人あたり: {}", 
         summery_izakaya_integer, number_of_person_integer, price_one_person_integer);
```
出力: 
```
飲み台の合計: 13423,人数は: 6, 一人あたり: 2237
```

小数点どうしの場合は、そのまま小数点まで計算されます。
```
    let summery_izakaya_float = 13423.0;
    let number_of_person_float = 6.0;
    let price_one_person_float = summery_izakaya_float / number_of_person_float;

    println!("飲み台の合計: {},人数は: {}, 一人あたり: {}", 
        summery_izakaya_float, number_of_person_float, price_one_person_float);
```
出力: 
```
飲み代の合計: 13423,人数は: 6, 一人あたり: 2237.1666666666665
```

・剰余算
剰余算は % の記号を使います。
計算の優先順位は () で指定します。()で囲った式が先に計算されます。
```
    //剰余算
    let goukei_kingaku = 9843;
    let ninzu = 5;
    let hasuu = goukei_kingaku % 500;
    let hitori_atari = (goukei_kingaku - hasuu) / ninzu;

    println!("飲み代の合計: {},人数は: {}, 一人あたり: {}, 端数: {}", 
    goukei_kingaku, ninzu, hitori_atari, hasuu);
```

出力
```
飲み代の合計: 9843,人数は: 5, 一人あたり: 1900, 端数: 343
```

## 04.02. 文字列(&str型)の取り扱い
文字列を取り扱います。
文字列を使えば、画面にメッセージを表示したりできます。
文字列は " " (ダブルクオーテーション)で囲みます。

文字列は、&str型(コンパイル時に内容と長さが決まる型)と、String型(実行中にデータの変更が可能)があります。
ここでは、&strとして扱う型を取り扱います。

```
fn main() {
    let message_a = "hello";
    let message_b = "world";
    
    println!("{}{}{}", message_a, "--" , message_b);

    println!("{}の長さは: {} byte", message_a, message_a.len());
    println!("{}の長さは: {} byte", message_b, message_b.len());

    let message_c = "こんにちわ";
    let message_d = "世界";
    
    println!("{}{}{}", message_c, "、" , message_d);

    println!("{}の長さは: {} byte", message_c, message_c.len());
    println!("{}の長さは: {} byte", message_d, message_d.len());
}
```
出力
```
hello--world
helloの長さは: 5 byte
worldの長さは: 5 byte
こんにちわ、世界
こんにちわの長さは: 15 byte
世界の長さは: 6 byte
```

●解説

&str型の文字列を束縛する変数の定義です。固定長なので、スタックに確保されます。
```
    let message_a = "hello";
    let message_b = "world";
    
    println!("{}{}{}", message_a, "--" , message_b);
```

出力
```
hello--world
```

次のように型を指定して定義してもよいです。
```
    let message_a: &str = "hello";
    let message_b: &str = "world";
```

文字列の長さは .len() で取得できます。単位はバイトです。
```
    println!("{}の長さは: {} byte", message_a, message_a.len());
    println!("{}の長さは: {} byte", message_b, message_b.len());
```

出力
```
helloの長さは: 5 byte
worldの長さは: 5 byte
```

ここで紹介する文字列は、あまり大したことはできません。本格的な取り扱いはString型で行うことになるでしょう。

## 04-03. 文字の取り扱い
文字は文字列の中の文字の1文字だけのデータです。
文字は char 型で扱います。このデータもスタックに積まれます。

```main.rs
fn main() {
    let moji_a = '6';
    let moji_b = 'k';
    let moji_c = 'は';
    let moji_d = '羅';
    let moji_e = '🥺';

    println!("1文字目: {}, 2文字目: {}, 3文字目: {}, 4文字目: {}, 5文字目: {}  ",
    moji_a, moji_b, moji_c, moji_d, moji_e);

    println!("文字のサイズ(byte)");
    println!("1文字目の: {}, 2文字目: {}, 3文字目: {}, 4文字目: {}, 5文字目: {}  ",
    moji_a.len_utf8(), moji_b.len_utf8(), moji_c.len_utf8(), moji_d.len_utf8(), moji_e.len_utf8());

}

```

出力
```
1文字目: 6, 2文字目: k, 3文字目: は, 4文字目: 羅, 5文字目: 🥺  
```

●解説

文字は ' ' (シングルクオーテーション)で囲みます。

```
    let moji_a = '6';
    let moji_b = 'k';
```

日本語などの多バイト文字も文字として扱えます。
```
    let moji_c = 'は';
    let moji_d = '羅';
```

emojiもいけます。
```
    let moji_e = '🥺';
```

println!()で普通に表示できます。
```
    println!("1文字目: {}, 2文字目: {}, 3文字目: {}, 4文字目: {}, 5文字目: {}  ",
    moji_a, moji_b, moji_c, moji_d, moji_e);
```
出力
```
1文字目: 6, 2文字目: k, 3文字目: は, 4文字目: 羅, 5文字目: 🥺  
```

文字のサイズは、.len_utf8() で取得できるようです。
```
    println!("文字のサイズ(byte)");
    println!("1文字目の: {}, 2文字目: {}, 3文字目: {}, 4文字目: {}, 5文字目: {}  ",
    moji_a.len_utf8(), moji_b.len_utf8(), moji_c.len_utf8(), moji_d.len_utf8(), moji_e.len_utf8());

```

出力
```
1文字目の: 1, 2文字目: 1, 3文字目: 3, 4文字目: 3, 5文字目: 4 
```

## 04-04. シャドーイング


```
$ cargo new shadowing
     Created binary (application) `shadowing` package
```

同じ変数名をつかって別の変数を作ることが出来ます。つまり、同じ名前の変数を再定義できます。
（他の多くのプログラミング言語では、2重定義エラーとなります）

再定義すると、前の値が再定義した値に覆い隠されます。

```main.rs
fn main() {
    //値を代入して束縛
    let data = 5;
    println!("dataの値: {}", data);

    //同じ変数名を使って別の値を束縛(シャドーイング)
    let data = "hello world!";
    println!("dataの値: {}", data);


    //同じ変数名を使って別の値を束縛(シャドーイング)
    let data = 3.141592;
    println!("dataの値: {}", data);

    //なお、同じ変数に違う値を代入し束縛することもできる
    let mut data = 123;
    println!("dataの値: {}", data);

    data = 345;
    println!("dataの値: {}", data);

    //型が違うので代入できない
    //data = "hello"

}
```

出力
```
dataの値: 5
dataの値: hello world!
dataの値: 3.141592
dataの値: 123
dataの値: 345
```

●解説
変数dataをシャドウイングしていきます。
違う型でシャドーイングすることもできます。
シャドウイングしたら、最初にあった 5 というデータは、なくなります。
```
  //値を代入して束縛
    let data = 5;
    println!("dataの値: {}", data);

    //同じ変数名を使って別の値を束縛(シャドーイング)
    let data = "hello world!";
    println!("dataの値: {}", data);


    //同じ変数名を使って別の値を束縛(シャドーイング)
    let data = 3.141592;
    println!("dataの値: {}", data);
```
出力
```
dataの値: 5
dataの値: hello world!
dataの値: 3.141592
```

イミュータブルだった変数を、ミュータブルでシャドウイングしてもいいです。
なお、シャドーイングは、変数の値を再代入することとは違います。次の 「data = 345」というコードは、シャドウイングではありません。
```
    //なお、同じ変数に違う値を代入し束縛することもできる
    let mut data = 123;
    println!("dataの値: {}", data);

    data = 345;
    println!("dataの値: {}", data);
```
出力
```
dataの値: 123
dataの値: 345
```

シャドウイングをすれば、型の違う値を代入できますが、以下の場合はシャドウイングをしておらず、変数の型がちがうので代入できません。
```
    //型が違うので代入できない
    //data = "hello"
```

つづく