Rust ハッシュマップ

Hash Mapはキーと値のペアを複数保存する構造
キーを重複することはできない
ハッシュマップの主なメソッド
new(): 新しいハッシュマップを作る
with_capacity(): 指定した容量の空のハッシュマップを作る
 capacity(), keys(), values(), values_mut(), iter(), iter_mut(), len(), is_empty(), clear(), insert(), remove()

ハッシュマップの作成
use std::collections::HashMap;
空のハッシュマップを作成する書式
let mut boys = HashMap::new();

boys.insert(String::from(“ポチ”), 6);
boys.insert(String::from(“犬太”), 16);
boys.insert(String::from(“Tommy”), 14);

use std::collections::HashMap;

fn main(){
	let mut boys = HashMap::new();

	boys.insert(String::from("ポチ"), 6);
	boys.insert(String::from("犬太"), 16);
	boys.insert(String::from("Tommy"), 14);

	for (key, value) in &boys {
		println!("{}: {}", key, value);
	}
	println!("boys={:?}", boys);
	let name = String::from("ポチ");
	println!("ポチ={:?}", boys.get(&name));

	boys.insert(String::from("ポチ"), 8);
	println!("ポチ={:?}", boys.get(&name));
}

Rust ベクター

ベクターは複数要素を保存できるという点で配列と似ているが、要素を追加したり取り出したりして要素数を変更できるという点で配列より用途が広い。ただし、実行速度は配列より遅くなる傾向
let v = vec![1, 3, 5, 7, 9];
int n = v[2];
let nv = v.len();
let mut v = vec![1, 2, 3, 4, 5];
v.push(11); //最後に要素を追加
let x = v.pop; //末尾の要素を取り出す際はpopを使う
最初の要素はfirst(), 最後の要素はlast()で取り出す

fn main(){
	let mut v = vec![1, 2, 3, 4, 5];
	let n = v[2];
	println!("vのサイズ={}", v.len());
	println!("v={:?}", v);
	println!("v[2]={}", n);

	v.push(11);
	println!("push()後のvのサイズ={}", v.len());
	println!("push()後のv={:?}", v);

	let x = v.pop();
	println!("pop()後のvのサイズ={}", v.len());
	println!("pop()後のv={:?}", v);
	println!("pop()後のx={:?}", x);

	println!("v.first()={:?}", v.first());
	println!("v.last()={:?}", v.last());
	println!("vのサイズ={}", v.len());
}
fn main(){
	let mut v = vec!["Hello", "Dogs", "Happy", "Smart"];
	println!("v={:?}", v);
	println!("v[2]={}", v[2]);

	v.push("ポチ");
	println!("push()後のvのサイズ={}", v.len());
	println!("push()後のv={:?}", v);
}

Rust タプルと配列

### タプル
タプルは複数の異なる型の値を1つのグループにすることができる複合型
let t1 = (12, 24);
let t2 = (50, 0.8, 12);
let t3 = (23.0, “Hello”, 88, ‘あ’);

タプルの長さは一旦決定すると変更できない。個々の要素はピリオド(.)を使ってアクセスする

fn main(){
	let t1: (i32, f64, u8) = (50, 0.8, 12);
	let t2 = (123, 2.3, 10);
	println!("{} {} {}", t1.0, t2.1, t1.2);
	println!("{} {} {}", t2.0, t2.1, t2.2);
}

タプルから新しいタプルを作ることもできる

fn main(){
	let t2 = (123, 2.3, 10);
	let (x, y, z) = t2;
	println!("{} {} {}", x, y, z);
}

複合型の値は{:?}を指定することで全体を出力することができる

fn main(){
	let t: (i32, f64, u8) = (50, 0.8, 12);
	println!("{:?}", t);
}

mutを使って宣言したタプルの中に保存した値は、同じデータ型であれば変更できる

fn main(){
	let mut t = (12, 24);
	println!("{:?}", t);

	t.0 = 23;
	println!("{:?}", t);
}

変数を使ってタプルの要素にアクセスすることはできない

### 配列
配列(array)は同じ型の要素を並べたもの。長さは変えることができない
let a = [1, 2, 3, 4, 5];
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [3; 5];
let mut data = [0 as u8; 6] // 6バイトのu8型配列

fn main(){
	let mut data = [0 as u8; 6];

	data[1] = 12;
	data[3] = 34;
	data[5] = 56;

	println!("data={:?}", data);
}

実行時にならないとアクセスする要素のインデックスが決定しない場合は、コンパイル時にはエラーとして検出されず、実行時にパニックが発生する

forでrangeの代わりに配列のイテレータを指定することもできる

fn main(){
	let a = [1, 3, 5, 7, 9];
	for i in a.iter(){
		println!("{}の2乗は{}", i, i*i);
	}
}

for文のrangeに配列の要素数を指定して繰り返しても構わない

fn main(){
	const NDATA:usize = 5;
	let mut data = [0; NDATA];
	for i in 0..NDATA {
		data[i] = i;
	}
	println!("{:?}", data);
}

Rust 繰り返し(for, while, loop)

通常繰り返しにはfor文、while文、loop文を使用する。

fn main(){
	for i in 0..10 {
		println!("{}の2乗は{}", i, i*i);
	}
}

if文と同様に結果を返すことができる

fn main(){
	let x = for i in 0..10 {
		println!("{}の2乗は{}", i, i*i);
	};
	println!("{:?}", x);
}

for文の中にfor文を記述するネストもできる。

fn main(){
	for i in 0..10 {
		let mut v = 1;
		for j in 2..=i{
			v = v * j
		}
		println!("{}の階乗は{}", i, v);
	};
}

breakを使って繰り返し処理を終了することができる

fn main(){
	for i in 0..10 {
		if i > 5 {
			break
		}
		println!("{}", i);
	};
}

ラベルは先頭を単一引用符(‘)にする

fn main(){
'looptop:
	for i in 0..4 {
		for j in 0..4 {
			if i == 1 && j == 2 {
				break 'looptop;
			}
			println!("{} {}", i, j);
		}
	}
}

forループの中でcontinueを使うことで以降のコードを実行せずにループの先頭に戻ることができる。

fn main(){
	for i in 0..10 {
		if i % 2 == 0 {
			continue
		}
		println!("{}", i);
	}
}

配列の繰り返し

fn main(){
	let fruits = ["りんご", "みかん", "バナナ"];
	for x in fruits.iter(){
		println!("{}", x);
	}
}

ベクターでも同じようにイテレータを使うことができる

fn main(){
	let fruits = vec!["りんご", "みかん", "バナナ"];
	for x in fruits.iter(){
		println!("{}", x);
	}
}

3回出力する場合

fn main(){
	for _i in 1..4 {
		println!("Hello!");
	}
}
fn main(){
	for _ in 1..4 {
		println!("Hello!");
	}
}

While文

fn main(){
	let mut i = 0;
	while i < 10 {
		println!("{}", i);
		i = i + 1;
	}
}
fn main(){
	let mut i = 0;
	loop {
		println!("{}", i);
		i = i + 1;
		if i > 5 {
			break;
		}
	}
}

無限ループはbreakでループから抜けるか std::process::exit(1);で終了する

Rust if文, match文

条件分岐の式では、条件に応じて実行するコードを選択する
if expr {
statement
}

state_true, falseで実行するステートメントを分岐する
if is_even(n){
println!(“{}は偶数です”, n);
} else {
println!(“{}は奇数です”, n)
}

use std::io;

fn main(){
	println!("整数を入力してください。");

	let mut s = String::new();
	io::stdin().read_line(&mut s).ok();
	let x:i32 = s.trim().parse().ok().unwrap();

	if x > 0 {
		println!("{}は正の整数です。", x);
	} else if x < 0 {
		println!("{}は負の整数です。", x);
	} else {
		println!{"{}はゼロです。", x};
	}
}

値を返す場合はセミコロンを付けない

fn main(){
	let x = 0;

	let b = if x > 0 {
		println!("{}は正の値", x)
	} else {
		println!("{}はゼロまたは負の値", x)
	};

	println!("b={:?}", b);
}

### match文
match文は、式を評価して、結果に応じて処理を切り替える

fn main(){
	let n:i32 = 3;

	let x = n % 2;
	match x {
		0 => println!("{}は偶数です。", n),
		1 => println!("{}は奇数です。", n),
		_ => println!("{}は偶数でも奇数でもありません。", n),
	}
}

_のケースを記載しないとコンパイル時にエラーになる
その場合は、 _ => (),と書く

fn main(){
	let n:i32 = 3;

	match (n % 2) == 0 {
		true => println!("{}は偶数です。", n),
		false => println!("{}は奇数です。", n),
	}
}
fn main(){
	let n:u16 = 3;

	match n {
		0 => println!("{}はゼロです。", n),
		1..=9 => println!("{}は10未満の整数です。", n),
		_ => println!("{}は10以上の整数です。", n),
	}
}

「|」を使って条件式に複数の値を指定することもできる

fn main(){
	let n:u16 = 3;

	match n {
		0 => println!("{}はゼロです。", n),
		1|3|5|7|9 => println!("{}は10以下の奇数です。", n),
		2|4|6|8|10 => println!("{}は10以下の偶数です。", n),
		_ => println!("{}は11以上の整数です。", n),
	}
}

Rust コマンドライン引数

コマンドライン引数は、std::env::args().collect()で取得することができる
let argv: Vec = std::env::args().collect();

use std::env;

fn main(){
	let argv: Vec<String> = env::args().collect();
	let argc = argv.len();
	println!("arg={}", argc);
	println!("{:?}", argv);
}

コマンド名とコマンドライン引数を表示する例

use std::env;

fn main(){
	let argv: Vec<String> = env::args().collect();
	let argc = argv.len();

	if argc < 3 {
		println!("引数を2個指定してください。");
		std::process::exit(1);
	}

	println!("実行ファイル名:{}", argv[0]);
	println!("引数1:{}", argv[1]);
	println!("引数2:{}", argv[2]);
}

コマンドラインからファイル名を取得してファイルを読み込んで表示する1つのツールとして使えるプログラムにする

use std::env;
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()>{
	let argv: Vec<String> = env::args().collect();
	let argc = argv.len();

	let fname = &argv[1];

	if argc < 2 {
		println!("引数にファイル名を指定してください。");
		std::process::exit(1);
	}

	let f = File::open(fname)?;
	let reader = BufReader::new(f);

	for line in reader.lines(){
		println!("{}", line?);
	}
	Ok(())
}

Rust コンソール入力

キーボードから文字列や数値を入力する方法
read_line()を使う
典型的には std::io::stdin().read_line(&mut line).ok();

fn main(){
	println!("名前を入力してください。");

	let mut line = String::new();
	std::io::stdin().read_line(&mut line).ok();
	let name = line.trim().to_string();

	println!("こんにちは、{}さん!", name);
}

文字列として受け取ってから整数に変換
let n:i32 = s.trim().parse().ok().unwrap();

fn main(){
	println!("整数を入力してください。");

	let mut s = String::new();
	std::io::stdin().read_line(&mut s).ok();
	let n:i32 = s.trim().parse().ok().unwrap();

	println!("{}の2倍は{}", n, n*2);
}

use文を使って予め宣言しておくと、「std::」を省略することができる

use std::io;

fn main(){
	println!("整数を入力してください。");

	let mut s = String::new();
	io::stdin().read_line(&mut s).ok();
	let n:i32 = s.trim().parse().ok().unwrap();

	println!("{}の2倍は{}", n, n*2);
}

use chrono::Local;
use chrono::DateTime;
use chrono::Date;

use chrono::{Local, DateTime, Date};

matchは値に従って実行するコードを切り替える

use std::io;

fn main(){
	println!("整数を入力してください。");

	let mut s = String::new();
	let rslt = io::stdin().read_line(&mut s);
	match rslt {
		Ok(v) => println!("読み込み成功: {:?}", v),
		Err(e) => println!("読み込み失敗: {:?}", e),
	}
	let n:i32 = s.trim().parse().ok().unwrap();

	println!("{}の2倍は{}", n, n*2);
}

Rust コンソール出力

fn main(){
	print!("abc");
	print!("123");
	print!("xyz");
}

書式指定文字

fn main(){
	let name = "ワンコ犬";
	println!("こんにちは、{}{}", name, "さん。");
}

{}で出力できる型は基本的にはスカラー型や文字列などの単純な型の値で、println!()やprint!()で出力できるようにstd::fmt::Displayで実装されている

fn main(){
	let name = "ワンコ犬";
	let age = 16;
	let l = 168.5;
	println!("{}:年齢={} 身長={}", name, age, l);
}
fn main(){
	let name = "ワンコ犬";
	let age = 16;
	let l = 168.5;
	println!("{0}:年齢={2} 身長={1}({0})", name, l, age);
}

基数の書式
b: 2進数、o: 8進数、x: 16進数、e: 指数表現

fn main(){
	println!("{:b}", 123);
	println!("{:o}", 123);
	println!("{:x}", 123);
	println!("{:X}", 123);
	println!("{:e}", 123);
	println!("{:E}", 123);
}

右寄せ、中央揃えなどの指定
n, ^n, >0n, <0n [code] fn main(){ println!("[{0:<8}]", "Left"); println!("[{0:^8}]", "Center"); println!("[{0:>8}]", "Right"); println!("[{0:<08}][<{1:>8}]", 123,234); } [/code] 配列全体の出力 [code] fn main(){ let a = [0,1,2,3]; println!("a={:?}", a); } [/code] [code] fn main(){ let mut s = String::new(); s.insert_str(0, "Hello"); println!("{}", s); println!("{:?}", s); } [/code]

Rust 演算子

二項演算子は、演算子の左右の値に作用する
let c = a + b;
+, -, *, /, %, &, |, ^, <<, >>

fn main(){
	let a = 0b010010;
	let b = 0b000111;

	println!("{:08b}", a & b);
	println!("{:08b}", a | b);
	println!("{:08b}", a ^ b);
}

ビットのシフトは、各ビットを左または右にシフトする
右にシフトすると値が小さくなり、左にシフトすると値が大きくなる

fn main(){
	let n = 1;
	println!("{}", n << 1);
	println!("{}", n << 2);
	println!("{}", n << 3);

	let m = 300;
	println!("{}", m >> 1);
	println!("{}", m >> 2);
	println!("{}", m >> 3);
}

単項演算子は右側の値が左側の値に作用する
比較演算子は左右の値の比較
論理演算子は左右の値または右側の値に作業して論理値を返す
代入演算子は右の値を左の変数に代入する

参照と参照外し
&は変数の参照を表す。参照の値に「*」を付けると値そのものを指す

fn main(){
	let x:i32 = 456;
	let r = &x;

	println!("x={}, r={}, *r={:?}", x, r, *r);
}

値の型の出力にはtype_of()を使う

fn main(){
	let x:i32 = 456;
	let r = &x;

	println!("x={}, type={:?}", x, type_of(x));
	println!("r={}, type={:?}", r, type_of(r));
	println!("*r={}, type={:?}", *r, type_of(*r));
}

fn type_of<T>(_: T) -> &'static str {
	std::any::type_name::<T>()
}
fn main(){
	let x:i32 = 456;
	let ref r = x;

	println!("x={}, r={}, *r={:?}", x, r, *r);
}
fn main(){
	let mut x:i32 = 456;
	let y = &mut x;
	*y = 123;

	println!("y={}", y);
	println!("y={} x={}", y, x);
}

Rustのその他の演算子
!, &, *, +, ,, -, -=, ->, ., .., ..=, …, /, /=, :, ;, =, =>, @, |, ?

演算子の結合順序
* / % << >> &
+ – | ^
== != < <= >= >=
&&
||

Rust 型の変換

fn main(){
	let n: i32 = 12;
	let v: f32 = n as f32;
	println!("{}->{}", n, v);
}
fn main(){
	let v = 123.45;
	let n = v as i32;
	println!("{}->{}", v, n);
}
let v = 12.56_f64;

let n = v.floor() as i32;
let m = v.ceil() as i32;
let l = v.round() as i32;

整数型から別の整数型への変換

fn main(){
	let n: i32 = 12;
	let v: i64 = n as i64;
	println!("{}->{}", n, v);
}
fn main(){
	let n: i64 = i64::MAX;
	let v: i32 = n as i32;
	println!("{}->{}", n, v);
}

実数型から別の実数型に変換するときもasを使う。この時に誤差が発生する場合がある

fn main(){
	let x: f32 = 7.6;
	let y: f64 = x as f64;
	println!("{}->{}", x, y);
}

7.6->7.599999904632568

文字列から数値へ変換するにはparse().unwrap()を使用する

fn main(){
	let s = "123";
	let v: u32 = s.parse().unwrap();
	println!("{}->{}", s, v);
}

あるいは parse::().unwrap()を使用する

fn main(){
	let s: &str = "123";
	let n: i32 = s.parse::<i32>().unwrap();

	println!("{:?}->{}", s, n);
}

文字列からバイト値に変換するにはas_bytes()を使用する

fn main(){
	let s: &str = "0";
	let n: &[u8] = s.as_bytes();

	println!("{}->{:?}", s, n);
}

数値から文字列への変換は to_string() を使用する

fn main(){
	let n: i32 = 123;
	let s = n.to_string();

	println!("{}->{}", n, s);
}

バイト値から文字列へ変換するにはstd::str::from_utf8().unwrap()を使用する

fn main(){
	let n: &[u8] = &[0x33];
	let s: &str = std::str::from_utf8(n).unwrap();

	println!("{:?}->{}", n, s);
}