Rust Result型とOption型

### Result型
Resultは関数の処理の結果を表す列挙型で、関数が失敗する可能性があるときによく使われる

fn main(){
	let n = 8;
	let m = 2;
	match i32div(n, m){
		Ok(result) => println!("{}/{}={}", n, m, result),
		Err(msg) => println!("エラー:{}", msg),
	}
}

fn i32div(n: i32, m: i32) -> Result<i32, &'static str> {
	if m != 0 {
		Ok(n/m)
	} else {
		Err("ZEROで割ろうとしています")
	}
}

### main()関数の戻り値
他の関数と同じように値を返すことができる。返された値はOSが受け取る
main()の宣言で ->io::Result<()>を追加

use std::io;

fn main() -> io::Result<()> {
	let x = 0;
	let x > 0 {
		println!("{}は正の数です。", x);
		Ok(())
	} else {
		println!("{}は正の数ではありません。", x);
		Err(io::Error::new(io::ErrorKind::Other, "error!"))
	}
}

### Option型
Option型は値がない可能性がある値を表現する列挙型で、値があることを示すSome(T)

pub enum Option<T> {
	Some(T),
	None,
}
fn getvalue(a:&Vec<i32>, n: i32) -> Option<i32> {
	for x in a.iter(){
		if x == &n {
			return Some(n);
		}
	}
	None
}

fn main() {
	let a = vec![1, 3, 5, 7, 9];
	let n = 5;

	match getvalue(&a, n) {
		Some(result) => println!("値{}があります。", result),
		None => println!("値は{}はありません", n),
	}
}

Rust 関数

関数は何らかの処理を行なって必要に応じて結果を返す、名前が付けられた呼び出し可能な一連のプログラムコード
fn name([args: type])[->(returns)]{
statement,
expr
}
※argsは関数の引数, returnは戻り値の型

fn printi32 (n: i32) {
	println!("値は{}", n);
}

fn twice(n: i32) -> i32 {
	2 * n
}

関数を呼び出すときには引数に適切な値を指定して呼び出す

fn is_even(n: i32) -> bool {
	(n % 2) == 0
}

fn main(){
	let n = 12;

	if is_even(n){
		println!("{}は偶数です", n);
	} else {
		println!("{}は奇数です", n);
	}
}

複数の引数を使う関数

fn main(){
	let a = 2;
	let b = 3;
	let x = add(a, b);
	println!("a+b={}", x);
}

fn add(a: i32, b: i32) -> i32 {
	a + b
}

複数の戻り値を返す関数
-> 戻り値を囲んだタプルとして返す

fn main(){
	let a = 20;
	let b = 3;
	let (x, y) = divid(a, b);
	println!("a/b={}...{}", x, y);
}

fn divid(a: i32, b: i32) -> (i32, i32) {
	( a / b, a % b)
}

関数の最後に記述した式は関数の値として返すことができるが、関数の途中で値を返すことこもできる

use std::io;

fn main() {
	println!("整数を入力してください。");
	let mut s = String::new();
	io::stdin().read_line(&mut s).ok();
	let v:i32 = s.trim().parse().ok().unwrap();
	let x = abs(v);
	println!("abs({})={}", v, x);
}

fn abs(n: i32) -> i32 {
	if n < 0 {
		return -n
	}
	n
}

参照による引数の受け渡し

fn main() {
	let s = String::from("Hello");
	let x = get_length(&s);

	println!("{}の長さ={}", s, x);
}

fn get_length(x: &String)-> usize {
	x.len()
}

### ジェネリック引数の関数
関数の引数を任意の型にすることもできる
fn type_of(_: T) -> &’static str {
std::any::type_name::()
}

struct Point {
	x: i32,
	y: i32,
}

fn main() {
	let n = 1;
	println!("{}", type_of(n));
	let x = 7.0;
	println!("{}", type_of(x));
	let p = Point {x: 10, y: 20};
	println!("{}", type_of(p));
}

fn type_of<T>(_: T) -> &'static str {
	std::any::type_name::<T>()
}

### 戻り値を使った所有権の返却

fn main() {
	let mut msg = String::from("Hello");
	println!("msg={}", msg);
	msg = upper(msg);

	println!("msg={}", msg);
}

fn upper(s: String) -> String {
	println!("s={}", s.to_uppercase());
	s
}

### クロージャー
名前のない関数

move |x| {
	println!("x={}", x);
}

Rust 列挙型

列挙型(enum)は、特定の型の一連の値、または異なる型の一連の値を定義した型
enum DogKind {
AKITAINU,
SHIBAINU,
RETRIVER,
}

enum DogKind {
	AKITAINU,
	SHIBAINU,
	RETRIEVER,
}

fn main() {
	let dog1 = DogKind::AKITAINU;
	let dog2 = DogKind::SHIBAINU;

	match dog1 {
		DogKind::AKITAINU => println!("秋田犬"),
		DogKind::SHIBAINU => println!("柴犬"),
		DogKind::RETRIVER => println!("レトリバー"),
	}

	match dog2 {
		DogKind::AKITAINU => println!("秋田犬"),
		DogKind::SHIBAINU => println!("柴犬"),
		DogKind::RETRIVER => println!("レトリバー"),
	}

}

列挙子に種類の異なる型を指定したり、複数の値を持つように指定したりすることができる

enum Command {
	Quit,
	Move { x: i32, y: i32 },
	Write(String),
	SetColor(i32, i32, i32)
}

fn main(){
	let cmnds = vec![
		Command::Quit,
		Command::Move { x: 20, y: 30},
		Command::Write(String::from("Hello")),
		Command::SetColor {0:127, 1:127, 2:127}
	];

	for cmd in cmnds.iter(){
		match cmd {
			Command::Quit => println!("Quit"),
			Command::Move{x, y} => println!("Move {},{}", x, y),
			_ => println!("その他のコマンド"),
		}
	}
}
enum Option<T>{
	Some(T),
	None,
}

enum Result<T, E>{
	Ok(T),
	Err(E),
}

Rust 構造体

構造体はフィールドと呼ばれる要素の集まり
構造体はフィールド名と型を持つフィールドを複数持つ
struct Member {
id: String,
name: String,
age: i32,
}

let m = struct Member {
	id: String::from("A0101"),
	name: String::from("Pochi"),
	age: 12,
}
struct Member {
	id: String,
	name: String,
	age: i32,
}

fn main(){
	let m = Member {
		id: String::from("A0101"),
		name: String::from("Pochi"),
		age: 12
	};

	println!("id={:?}", m.id);
	println!("name={:?}", m.name);
	println!("age={:?}", m.age);
}
struct Member {
	id: String,
	name: String,
	age: i32,
}

fn main(){
	let mut m = Member {
		id: String::from("A0101"),
		name: String::from("Pochi"),
		age: 12
	};

	m.name = String::from("Pochi");
	m.age = 14;

	println!("id={:?}", m.id);
	println!("name={:?}", m.name);
	println!("age={:?}", m.age);
}
struct Point {
	x: i32,
	y: i32,
}

struct Circle {
	center: Point,
	radius: i32,
}

fn main(){
	let c = Circle {
		center: Point{x:10, y:20},
		radius: 25,
	};

	println!("(x,y)=({}, {})", c.center.x, c.center.y);
	println!("半径={}", c.radius);
}

### ジェネリック構造体
任意の型の値を扱えるようにする仕組みをジェネリックという

struct Point<T, U>{
	x: T,
	y: U,
}

fn main(){
	let p1 = Point { x: 20, y: 10};
	let p2 = Point { x: 5, y: 6.0};

	println!("p1.X={}, p1.y={}",p1.x, p1.y);
	println!("p2.X={}, p2.y={}",p2.x, p2.y);
}
struct Position<T, U, V>{
	x: T,
	y: U,
	z: V,
}

fn main(){
	let pos = Position { x: 5.0, y: 10, z:20.5};

	println!("X={}, y={}, z={}", pos.x, pos.y, pos.z);
}

### 共用体
メンバーが同じメモリ領域を使用するデータ構造

union MyData {
	va: u16,
	vb: u32,
}

fn main(){
	let v = MyData {vb: 0};

	unsafe {
		println!("v.va={}", v.va);
		println!("v.vb={}", v.vb);
	}
}

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(())
}