Rust eguiでグラフィックの利用

eguiのPainterという構造体を利用する

fn main() {
    let native_options = eframe::NativeOptions::default();
    native_options.default_theme = eframe::Theme::Light;
    native_options.initial_window_size = Some(egui::Vec2 {x:400.0, y:300.0});

    let _ = eframe::run_native("My egui App", native_options,
    	Box::new(|cc| Box::new(MyEguiApp::new(cc))));
}


#[derive(Default)]
struct MyEguiApp {
	pub value:bool,
}

impl MyEguiApp {
	fn new(_cc: &eframe::CreationContext<'_>)-> Self {
		Self::default()
	}
}

impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");
			plot(ui);
		});
	}
}

fn plot(ui: &mut egui::Ui){
	
}
fn plot(ui: &mut egui::Ui){
	ui.painter().rect_filled(
		egui::Rect::from_min_max(
			egui::Pos2::new(50.0, 50.0),
			egui::Pos2::new(150.0, 150.0)
		),
		egui::Rounding::same(20.0),
		egui::Color32::RED
	);
	ui.painter().rect_stroke(
		egui::Rect::from_min_max(
			egui::Pos2::new(100.0, 100.0),
			egui::Pos2::new(200.0, 200.0)
		),
		egui::Rounding::none(),
		egui::Stroke::new(10.0, egui::Color32::GREEN)
	);
}

円を表示する

fn plot(ui: &mut egui::Ui){
	let pos_1 = egui::Pos2::new(100.0, 100.0);
	ui.painter().circle_filled(pos_1, 50.0, egui::Color32::RED);
	let pos_2 = egui::Pos2::new(150.0, 150.0);
	let stroke_2 = egui::Stroke::from((10.0, egui::Color32::GREEN));
	ui.painter().circle_stroke(pos_2, 50.0, stroke_2);
}

直線を描く

fn plot(ui: &mut egui::Ui){
	let pos_1 = egui::Pos2::new(50.0, 50.0);
	let pos_2 = egui::Pos2::new(200.0, 200.0);
	let stroke_1 = egui::Stroke::new(5.0, egui::Color32::RED);
	let stroke_2 = egui::Stroke::new(5.0, egui::Color32::GREEN);
	ui.painter().vline(50.0, std::ops::RangeInclusive::new(50.0, 200.0), stroke_1);
	ui.painter().hline(std::ops::RangeInclusive::new(50.0, 200.0), 50.0, stroke_1);
	ui.painter().line_segment([pos_1, pos_2], stroke_2);
}

テキストを表示

fn plot(ui: &mut egui::Ui){
	ui.painter().text(
		egui::Pos2 {x:50.0, y:50.0},
		egui::Align2::LEFT_CENTER,
		"Hello!",
		egui::FontId::proportional(24.0),
		egui::Color32::RED
	);
	ui.painter().text(
		egui::Pos2 {x:50.0, y:100.0},
		egui::Align2::LEFT_CENTER,
		"sample message.",
		egui::FontId::proportional(36.0),
		egui::Color32::BLUE
	);
}

シェイプの利用

fn plot(ui: &mut egui::Ui){
	let data = vec![
		egui::Pos2::new(50.0, 100.0),
		egui::Pos2::new(250.0, 100.0),
		egui::Pos2::new(75.0, 225.0),
		egui::Pos2::new(150.0, 50.0),
		egui::Pos2::new(225.0, 225.0)
	];
	let stroke_1 = egui::Stroke::new(5.0, egui::Color32::RED);

	let mut shape_1 = eframe::epaint::PathShape::line(data, stroke_1);
	shape_1.closed = true;
	ui.painter().add(shape_1);
}

クリックした位置に描く

impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");
			let resp = ui.allocate_response(egui::vec2(400.0, 300.0), egui::Sense::click());
			if resp.clicked(){
				let p = resp.interact_pointer_pos().unwrap();
				self.click_pos.push(p);
			}
			plot(ui, &self.click_pos);
		});
	}
}

fn plot(ui: &mut egui::Ui, pos: &Vec<egui::Pos2>){
	for p in pos {
		ui.painter().circle_filled(*p, 25.0,
			egui::Color32::from_rgba_premultiplied(255, 0, 0, 100));
	}
}

Rust eguiで主なeguiを利用

fn main() {
    let native_options = eframe::NativeOptions::default();
    native_options.default_theme = eframe::Theme::Light;
    native_options.initial_window_size = Some(egui::Vec2 {x:400.0, y:200.0});

    let _ = eframe::run_native("My egui App", native_options,
    	Box::new(|cc| Box::new(MyEguiApp::new(cc))));
}

impl Default for MyEguiApp {
	fn default() -> MyEguiApp {
		MyEguiApp {
			value:0,
		}
	}
}

#[derive(Default)]
struct MyEguiApp {
	pub value:usize,
}

impl MyEguiApp {
	fn new(_cc: &eframe::CreationContext<'_>)-> Self {
		Self::default()
	}
}

impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");

			ui.spacing();

			let msg = format!("click {} times.", self.value);
			let label_txt = egui::RichText::new(msg)
				.size(32.0);
			let label = egui::Label::new(label_txt);
			ui.add(label);

			ui.separator();

			let btn_txt = egui::RichText::new("Click!")
				.font(egui::FontId::proportional(24.0));
			let btn = egui::Button::new(btn_txt);
			let resp = ui.add_sized(egui::Vec2{x:150.0, y:40.0}, btn);
			if resp.clicked() {
				self.value += 1;
			}
		});
	}
}

チェックボックス

impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");

			ui.spacing();

			let msg = format!("checked = {}.", self.value);
			let label_txt = egui::RichText::new(msg)
				.size(32.0);
			let label = egui::Label::new(label_txt);
			ui.add(label);

			ui.separator();

			let check_txt = egui::RichText::new("checkbox")
				.size(24.0);
			let check = egui::Checkbox::new(&mut self.value, check_txt);
			let _resp = ui.add(check);
		});
	}
}

ラジオボタン、スライダー、ドラッグバリュー、選択ラベル、テキストエディット、パスワードなども

Rust eguiの基本

RustのフレームワークにはTauri, Druid, egiなどがある

### eguiを準備
Cargo.tomlのdependenciesを修正
eframeとeguiの2つのパッケージをインストールする
eframeはアプリケーション開発の基本機能を提供、eguiはguiライブラリ

[dependencies]
eframe = "0.21.0"
egui = "0.21.0"

アプリケーションの実行はeframeのrun_nativeを使う
eframe::run_native(name, , )
nativeOptionsはオプション設定などの情報管理
AppCreatorは構造体
AppCreatorのBox生成

### アプリの実行

fn main() {
    let native_options = eframe::NativeOptions::default();
    let _ = eframe::run_native("My egui App", native_options,
    	Box::new(|cc| Box::new(MyEguiApp::new(cc))));
}

#[derive(Default)]
struct MyEguiApp {}

impl MyEguiApp {
	fn new(_cc: &eframe::CreationContext<'_>)-> Self {
		Self::default()
	}
}

impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){}
}
impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");
		})
	}
}

テーマを変える

fn main() {
    let native_options = eframe::NativeOptions::default();
    native_options.default_theme = eframe::Theme::Light;
    let _ = eframe::run_native("My egui App", native_options,
    	Box::new(|cc| Box::new(MyEguiApp::new(cc))));
}

ラベルのテキストサイズを変更

impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");
			let label_txt = egui::RichText::new("This is sample message.")
				.font(egui::FontId::proportional(32.0));
			let label = egui::Label::new(label_text);
			ui.add(label);
		});
	}
}
impl eframe::App for MyEguiApp {
	fn update(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame){
		egui::CentralPanel::default().show(ctx, |ui|{
			ui.heading("Hello World!");
			let label_txt = egui::RichText::new("This is sample message.")
				.size(32.0)
				.color(egui::Color32::from_rgba_premultiplied(255,0,0,100))
				.italics();
			let label = egui::Label::new(label_text);
			ui.add(label);
		});
	}
}

Rustモジュールの作成

クレート: 配布するライブラリなどの配布単位となるもの。ライブラリ群はクレートとしてまとめられている。
モジュール: クレート内に用意されているライブラリ群
useを使い、クレートとその中にある利用したいモジュールをインポートすることで利用可能になる

$ cargo new –lib mymodule

use mymodule::add;

fn main() {
	let x = 10;
	let y = 20;
	let res = add(x, y);
	println!("answer: {} + {} = {}", x, y, res);
}

calcモジュールの中にadd関数を置く

pub mod calc {
	pub fn add(left: usize, right: usize) -> usize {
	    left + right
	}
}

モジュールのテストはcargo testで実行する
use super::*; は親モジュール内の全てのモジュールをインポートする

### テスト用のマクロ
assert_eq!()
assert_ne!()
assert!()

pub mod calc {

	pub fn is_prime(num: unsize) -> bool {
		let mut f = true;
		for n in 2..(num/ 2) {
			if num % n == 0 {
				f = false;
			}
		}
		return f;
	}
}

テストコード

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_is_prime() {
    	let data = [
    		2, 3, 5, 7, 11, 13, 17, 19, 23, 29
    	];

    	for n in data {
    		let res = calc::is_prime(n);
    		assert_eq!(res, true);
    	}
    }
    #[test]
    fn it_isnot_prime() {
    	let data = [
    		4, 6, 9, 10, 12, 14, 15, 16, 18, 20 
    	];

    	for n in data {
    		let res = calc::is_prime(n);
    		assert_eq!(res, true);
    	}
    }
}

Rustファイルアクセス

stdクレートのfsモジュールに必要な機能がまとめられている
use std::fs::File;

fileが得られたら、BufReader構造体のインスタンスを作成する
use std::io::{BufRead, BufReader}

data.txt

Hello!
This is sample text file
It takes text and display it.
file end.

data.txtを読み込み表示する

use std::fs::File;
use std::io::{BufRead, BufReader};

fn main(){
	let file = File::open("data.txt").unwrap();
	let reader = BufReader::new(file);

	let mut count = 0;
	for line in reader.lines() {
		count += 1;
		let txt = line.unwrap();
		println!("{}: {}", count, txt);
	}
}

### File取得とエラー処理

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::io::ErrorKind;

fn main(){
	let file = match File::open("data.txt") {
		Ok(file) => file,
		Err(error) => match error.kind(){
			ErrorKind::NotFound => panic!("ファイルが見つかりませんでした"),
			ErrorKind::PermissionDenied => panic!("ファイルへのアクセス権限がありません"),
			_ => panic!("ファイルのオープンに失敗しました:{:?}", error),
		},
	};

	let reader = BufReader::new(file);

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

### ファイルにテキストを保存する

use std::fs::File;
use std::io::Write;

fn main(){
	let data = [
		"Hello world!",
		"これはサンプルデータです。",
		"テストテスト!"
	];
	let str_data = data.join("\n");
	let mut file = File::create("backup.txt").unwrap();
	file.write_all(str_data.as_bytes()).unwrap();
}

### ファイルにデータを追記する

use std::fs::OpenOptions;
use std::io::Write;

fn main() {
	let str_data = "This is sample!\n";
	let mut file = OpenOptions::new()
		.create(true)
		.append(true)
		.open("append.txt").unwrap();
	file.write_all(str_data.as_bytes()).unwrap();
}

### ファイル一覧の取得

use std::fs;

fn main() {
	let paths = fs::read_dir("./").unwrap();

	for path in paths {
		let entry = path.unwrap();
		println!("{:?}", entry.path().to_str());
	}
}

### エントリーの種類を調べる

use std::fs;

fn main() {
	let paths = fs::read_dir("./").unwrap();

	for path in paths {
		let entry = path.unwrap();
		let ftype = entry.file_type().unwrap();
		if ftype.is_file() {
			println!("{:?} file", entry.path())
		} else if ftype.is_dir(){
			println!("{:?} dir", entry.path())
		} else if ftype.is_symlink() {
			println!("{:?} link", entry.path())
		} else {
			println!("{:?}", entry.path())
		}
	}
}

### ファイル/フォルダの操作
fs::create_dir(), fs::copy(), fs::move(), fs::remove_file(), fs::remove_dir(), fs::remove_dir_all()

use std::fs;

fn main() {
	_ = fs::create_dir("./backup");
	let entries = fs::read_dir("./").unwrap();

	for path in entries {
		let entry = path.unwrap();
		if entry.file_type().unwrap().is_file(){
			let file_name = entry.file_name();
			let from_name = format!("./{}", file_name.to_string_lossy());
			let to_name = format!("./backup/_{}", file_name.to_string_lossy());

			_ = fs::copy(&from_name, &to_name);
			println!("backup: {:?} -> {}", from_name, to_name);
		} else {
			println!("not copied.({:?})", entry.file_name());
		}
	}
}

Rustマルチスレッドと非同期処理

処理を行うために実行されるのがスレッド
プロセスが開始されると「メインスレッド」と呼ばれるアプリの基本となる処理を実行するスレッドが実行され、この中で処理が行われる
同時に複数の処理を並行して実行する必要があるときはマルチスレッドになる

### threadによるスレッド作成
スレッドの作成は「std」というクレートに用意されている「thread」というモジュールを使う

use std::thread;

fn main() {
	thread::spawn(|| {
		println!("THread:Start!");
		println!("THread:End!");
	});

	println!("Main:Start!");
	println!("Main:End.");
}

別スレッドの実行前にメインスレッドが終了している

### スレッドの一時停止とDuration
スレッドの処理を一時的に定するには、threadの「sleep」という関数を使用する
thead::sleep(Duration:)

use std::thread;
use std::time::Duration;

fn main() {
	thread::spawn(|| {
		println!("THread:Start!");
		thread::sleep(Duration::from_millis(10));
		println!("THread:End!");
	});

	println!("Main:Start!");
	thread::sleep(Duration::from_millis(100));
	println!("Main:End.");
}

どのスレッドが処理を実行中で、どれが終了したかを常に頭に入れて処理を行う必要がある

両スレッドの実行順序を確認

use std::thread;
use std::time::Duration;

fn main() {
	thread::spawn(|| {
		for n in 1..10 {
			println!("Thread:No, {}", n);
			thread::sleep(Duration::from_millis(50));
		}
	});

	for n in 1..10 {
		println!("Main: No,{}.", n);
		thread::sleep(Duration::from_millis(100))
	}
}

sleepの持つ役割

use std::thread;
use std::time::Duration;

fn main() {
	thread::spawn(|| {
		for n in 1..100 {
			println!("Thread:No, {}", n);
		}
	});
	thread::sleep(Duration::from_millis(1));

	for n in 1..100 {
		println!("Main: No,{}.", n);
	}
}

スレッドが一時停止した時などに動く

joinHandleとjoinメソッド

use std::thread;
use std::time::Duration;

fn main() {
	println!("Main:Start!");

	let h = thread::spawn(||{
			thread::spawn(|| {
				for n in 1..6 {
					println!("Thread:No, {}", n);
					thread::sleep(Duration::from_millis(2));
				}
			});

			thread::spawn(|| {
				for n in 1..6 {
					println!("H2:No,{}", n);
					thread::sleep(Duration::from_millis(2));
				}
			});

			for n in 1..6 {
				println!("Thread:No,{}", n);
				thread::sleep(Duration::from_millis(1));
			}
	});

	let _res = h.join();
	println!("Main:End.");
}

スレッドによる値の共有

use std::thread;
use std::time::Duration;

fn main() {
	let mut num = 1;
	println!("Main:Start!");

	let h1 = thread::spawn(move || {
		println!("H1: start!");
		for n in 1..5 {
			num = 10 * n;
			println!("H1: num_h={}.", num);
			thread::sleep(Duration::from_millis(10));
		}
		println!("H1: End.");
	});

	let h2 = thread::spawn(move || {
		println!("H2:Start!");
		for n in 1..5 {
			num += n;
			println!("H2: num_h={}.", num);
			thread::sleep(Duration::from_millis(10));
		}
		println!("H2: End.");
	});

	let _res = h1.join();
	let _res = h2.join();
	println!("Main:End.");
}

### Arc/Mutexで値を共有
Mutexはスレッド間でデータを共有する際のデータ保護を行うために用いられる構造体

use std::sync::{Mutex, Arc};
use std::thread;
use std::time::Duration;

fn main(){
	let num = Arc::new(Mutex::new(1));
	println!("Main start!");

	let num_1 = Arc::clone(&num);

	let h1 = thread::spawn(move || {
		let mut num_h1 = num_1.lock().unwrap();
		println!("H1: start!");
		for n in 1..5 {
			*num_h1 += n;
			println!("H1: num_h={}.", *num_h1);
			thread::sleep(Duration::from_millis(1));
		}
		println!("H1: End.");
	});

	let num_2 = Arc::clone(&num);

	let h2 = thread::spawn(move || {
		let mut num_h2 = num_2.lock().unwrap();
		println!("H2: start!");
		for n in 1..5 {
			*num_h2 *= n;
			println!("H2: num_h={}", *num_h2);
			thread::sleep(Duration::from_millis(1));
		}
		println!("H2: End.");
	});

	let _res = h1.join();
	let _res = h2.join();

	println!("Main:: End.");
}

スレッドのデッドロック

use std::sync::{Mutex, Arc};
use std::thread;
use std::time::Duration;

fn main(){
	let num1 = Arc::new(Mutex::new(0));
	let num2 = Arc::new(Mutex::new(0));

	let value1a = Arc::clone(&num1);
	let value2a = Arc::clone(&num2);

	let value1b = Arc::clone(&num1);
	let value2b = Arc::clone(&num2);

	let h1 = thread::spawn(move || {
		let mut num1 = value1a.lock().unwrap();
		thread::sleep(Duration::from_millis(50));
		let mut num2 = value2a.lock().unwrap();
		*num1 += 10;
		*num2 += 20;
	});

	let h2 = thread::spawn(move || {
		let mut num2 = value2b.lock().unwrap();
		thread::sleep(Duration::from_millis(50));
		let mut num1 = value1b.lock().unwrap();
		*num1 += 100;
		*num2 += 200;
	});

	h1.join().unwrap();
	h2.join().unwrap();

	println!("end");
}

チャンネルの利用

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main(){
	let (tx, rx) = mpsc::channel();
	println!("Main: start!");
	let h1 = thread::spawn(move ||{
		let mut num = 1;
		println!("H1: start!");
		for n in 1..5 {
			num += n;
			tx.send(num).unwrap();
			println!("H1: num={}.", num);
			thread::sleep(Duration::from_millis(10));
		}
		println!("H1: End.");
	});

	let h2 = thread::spawn(move ||{
		println!("H2: start!");
		for n in 1..5 {
			let num_recv = rx.recv().unwrap();
			println!("H2: num_recv={}.", num_recv);
			thread::sleep(Duration::from_millis(20));
		}
		println!("H2: End.");
	});
	let _res = h1.join();
	let _res = h2.join();
	println!("Main: End.");
}

相互に送受信

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main(){
	let (tx1, rx1) = mpsc::channel();
	let (tx2, rx2) = mpsc::channel();
	tx2.send(0).unwrap();
	println!("Main: start!");

	let h1 = thread::spawn(move ||{
		let mut num = 1;
		println!("H1: start!");
		for n in 1..5 {
			let val = rx2.recv().unwrap();
			num += n;
			println!("H1: num={}.", num);
			tx1.send(num).unwrap();
			thread::sleep(Duration::from_millis(10));
		}
		println!("H1: End.");
	});
	thread::sleep(Duration::from_millis(5));
	let h2 = thread::spawn(move ||{
		println!("H2: start!");
		for n in 1..5 {
			let val = rx1.recv().unwrap();
			let num = val * 2;
			println!("H2: num={}.", num);
			tx2.send(num).unwrap();
			thread::sleep(Duration::from_millis(10));
		}
		println!("H2: End.");
	});
	let _res = h1.join();
	let _res = h2.join();
	println!("Main: End.");
}

### 同期チャンネル

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main(){
	let (tx1, rx1) = mpsc::sync_channel(1);
	let (tx2, rx2) = mpsc::sync_channel(1);
	tx2.sync_send(0).unwrap();
	println!("Main: start!");

	let h1 = thread::spawn(move ||{
		let mut num = 1;
		println!("H1: start!");
		for n in 1..5 {
			let val = rx2.recv().unwrap();
			num += n;
			println!("H1: num={}.", num);
			tx1.sync_send(num).unwrap();
			thread::sleep(Duration::from_millis(10));
		}
		println!("H1: End.");
	});
	thread::sleep(Duration::from_millis(5));
	let h2 = thread::spawn(move ||{
		println!("H2: start!");
		for n in 1..5 {
			let val = rx1.recv().unwrap();
			let num = val * 2;
			println!("H2: num={}.", num);
			tx2.sync_send(num).unwrap();
			thread::sleep(Duration::from_millis(10));
		}
		println!("H2: End.");
	});
	let _res = h1.join();
	let _res = h2.join();
	println!("Main: End.");
}

Noneとエラー処理

fn main() {
	let mut data = vec![];
	for n in 0..5 {
		data.push(Some(n));
	}
	print_all(data);
}

fn print_all(data:Vec<Option<i32>>) {
	for item in data {
		println!("{:?}", item);
	}
}

Noneを含む処理

use rand::Rng;

fn random()-> Option<i32> {
	let n = rand::thread_rng().gen_range(0..10);
	match n {
		0 => None,
		_ => Some(n)
	}
}

fn main() {
	let mut data = vec![];
	for n in 0..10 {
		data.push(random(n));
	}
	print_all(data);
}

fn print_all(data:Vec<Option<i32>>) {
	for item in data {
		print(item);
	}
}

fn print(item:Option<i32>){
	match item {
		None => println!("no-data..."),
		Some(n) => println!("No, {}.", n)
	}
}

### Panicによる強制終了

fn print(item:Option<i32>){
	match item {
		None => panic!("NODATA!"),
		Some(n) => println!("No, {}.", n)
	}
}

### Resultによるエラーリカバリ

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

Errを使ってエラー処理を行う

fn print(item:Option<i32>)->Result<String, String>{
	match item {
		None => {
			Err(String::from("ERROR IS OCCURED."))
		},
		Some(n) => {
			println!("No, {}.", n);
			Ok(String::from("OK"))
		}
	}
}

### print_allでResultによるエラー処理を実装

fn print_all(data:Vec<Option<i32>>) {
	for item in data {
		let res = print(item);
		match res {
			Ok(s) => println!("--- {} ---", s),
			Err(s) => println!("*** {} ***", s)
		}
	}
}

### より細かなエラー処理
enum ErrKin {
Caution,
Danger
}

fn print_all(data:Vec<Option<i32>>) {
	for item in data {
		let res = print(item);
		match res {
			Ok(s) => println!("--- {} ---", s),
			Err(s) => match k {
				ErrKind::Caution => {
					println!("*** CAUTION!! ***");
				},
				ErrKind::Danger => {
					println!("DANGER!!");
					panic!("DANGER ERROR.");
				}
			}
		}
	}
}

fn print(item:Option<i32>)->Result<String, ErrKind>{
	match item {
		None => {
			Err(ErrKind::Danger)
		},
		Some(n) => {
			println!("No, {}.", n);
			if n == 1 {
				Err(ErrKind::Caution)
			} else {
				Ok(String::from("OK"))
			}
		}
	}
}

Rustジェネリクス

様々な型に対応できる処理に対応できるのがジェネリクス

#[derive(Debug)]
struct Sample<T> {
	name:String,
	value:T
}

fn main() {
	let taro = Sample {
		name:String::from("Taro"),
		value:String::from(("this is message."))
	};
	let hanako = Sample {
		name:String::from("Hanako"),
		value: 1234
	};
	println!("{:?}", taro);
	println!("{:?}", hanako);
}

SampleにVecフィールドを追加する

#[derive(Debug)]
struct Sample<T:core::fmt::Debug> {
	name:String,
	value:Vec<T>
}

impl<T:core::fmt::Debug> Sample<T> {
	fn print_values(&self) {
		println!("*** {} ***", &self.name);
		for item in &self.values {
			println!("{:?}", item);
		}
	}
}

fn sample<T:core::fmt::Debug>(name:&str, values:Vec<T>)
	-> Sample<T>{
		Sample{name:String::from(name), values:values}
	}

fn main() {
	let taro = sample("Taro",
		vec![123, 456, 789]);
	taro.print_values();
	let hanako = sample("Hanako",
		vec!["Hello", "Welcome", "Bye!"]);
	hanako.print_values();
}
trait Print {
	fn print(&self) {
		println!("not implmented...");
	}
}

struct Person {
	name: String,
	mail: String,
	age: i32
}

struct Student {
	name: String,
	mail:String,
	grade: i32
}

impl Print for Person {
	fn print(&self) {
		println!("Person: {}<{}>({})", &self.name, &self.mail, &self.age);
	}
}

impl Print for Student {
	fn print(&self) {
		println!("Student [grade {}]{}<{}>", &self.grade, &self.name, &self.mail);
	}
}

fn person(name:&str, mail:&str, age:i32)->Box<Person>{
	Box::new(Person{name:String::from(name), mail:String::from(mail), age:age})
}

fn student(name:&str, mail:&str, grade:i32)->Box<Student>{
	Box::new(Student{name:String::from(name), mail:String::from(mail), grade})
}

Rustトレイト

トレイトは実装を抽象化したもの
trait トレイト {
fn 関数(引数);
fn 関数(引数);
}

trait Print {
	fn print(&self);
}

struct Person {
	name:String,
	mail:String,
	age:i32
}

impl Print for Person {
	fn print(&self) {
		println!("{}<{}>({}).", self.name, self.mail, self.age);
	}
}

fn person(name:String, mail:String, age:i32)-> Person {
	Person {name, mail, age}
}

struct Student {
	name:String,
	mail:String,
	grade:i32
}

impl Print for Student {
	fn print(&self) {
		println!("grade{}: {}<{}>.", self.grade, self.name, self.mail);
	}
}

fn student(name:String, mail:String, grade:i32)-> Student {
	Student {name, mail, grade}
}

fn main(){
	let taro = person {
		String::from("Taro"),
		String::from("taro@yamada"),
		39
	};
	let hanako = person {
		String::from("Hanako"),
		String::from("hanako@flower"),
		28
	};
	taro.print();
	hanako.print();
}

### 汎用トレイトとderive属性

#[derive(Debug)]
struct Person {
	name:String,
	mail:String,
	age:i32
}

#[derive(Debug)]
struct Student {
	name:String,
	mail:String,
	grade:i32
}

fn person(name:&str, mail:&str, age:i32)->Person {
	Person{name:String::from(name), mail:String::from(mail), age:age}
}

fn student(name:&str, mail:&str, grade:i32)->Student {
	Student{name:String::from(name), mail:String::from(mail), grade}
}

fn main() {
	let taro = person("Taro", "taro@yamada", 39);
	let hanako = student("Hanako", "hanako@flower", 2);
	println!("{:?}", taro);
	println!("{:?}", hanako);
}
trait Print {
	fn print(&self) {
		println!("PRINT is not yet implemented...");
	}
}

#[derive(Debug)]
struct Person {
	name:String,
	mail:String,
	age:i32
}

#[derive(Debug)]
struct Student {
	name:String,
	mail:String,
	grade:i32
}

impl Print for Person {
	fn print(&self) {
		println!("{}<{}>({}).", self.name, self.mail, self.age);
	}
}

impl Print for Student {}

fn person(name:&str, mail:&str, age:i32)->Person {
	Person{name:String::from(name), mail:String::from(mail), age:age}
}

fn student(name:&str, mail:&str, grade:i32)->Student {
	Student{name:String::from(name), mail:String::from(mail), grade}
}

fn main() {
	let taro = person("Taro", "taro@yamada", 39);
	let hanako = student("Hanako", "hanako@flower", 2);
	taro.print();
	hanako.print();
}

Rust構造体

異なる型の値を決まった構造で管理する
struct 構造体名{
フィールド名: 型,
フィールド名: 型,

}

struct Person {
	name: String,
	mail: String,
	age: i32
}

fn print_person(p:Person) {
	println!("I'm {}({}). Mail to {}.", p.name, p.age, p.mail);
}

fn main(){
	let taro = Person {
		name:String::from("Taro"),
		mail:String::from("taro@yamada"),
		age: 39
	};
	let hanako = Person {
		name:String::from("Hanako"),
		mail:String::from("hanako@flower"),
		age: 28
	};
	print_person(taro);
	print_person(hanako);

}

### タプル構造体
構造体名の後にタプル()で記述する

struct Person (String, String, i32);

fn print_person(p:Person) {
	println!("I'm {}({}). Mail to {}.", p.0, p.2, p.1);
}

fn main(){
	let taro = Person (
		String::from("Taro"),
		String::from("taro@yamada"),
		39
	);
	let hanako = Person (
		String::from("Hanako"),
		String::from("hanako@flower"),
		28
	);
	print_person(taro);
	print_person(hanako);
}

構造体は値を保管するためのもの
implというブロックを使う

出力メソッドを実装

struct Person {
	name: String,
	mail: String,
	age: i32
}

fn person(name:String, mail:String, age)-> Person {
	Person {name, mail, age}
}

impl Person {
	fn print(&self) {
		println!("{}<{}>({}).", self.name, self.mail, self.age);
	}
}

fn main(){
	let taro = person {
		String::from("Taro"),

selfのない関数

struct Person {
	name: String,
	mail: String,
	age: i32
}

fn person(name:String, mail:String, age:i32)-> Person {
	Person {name, mail, age}
}

impl Person {
	fn print(&self) {
		println!("{}<{}>({}).", self.name, self.mail, self.age);
	}
	fn fields()->[String;3] {
		[
			String::from("name:String"),
			String::from("mail:String"),
			String::from("age:i32"),
		]
	}
}

fn main(){
	let taro = person {
		String::from("Taro"),
		String::from("taro@yamada"),
		39
	};
	let hanako = person {
		String::from("Hanako"),
		String::from("hanako@flower"),
		28
	};
	taro.print();
	hanako.print();
	println!("Person's fields: {:?}", Person::fields());
}