Rust 非同期実行

関数を非同期実行することができる
async/awaitは、時間のかかる処理をするときに、処理が終わるまでのスレッドを別のタスクの処理に使うことができる機能を提供する

use futures::executor::block_on;

fn wait() -> f64 {
	let mut x:f64 = 0.0;
	for _ in 1..10000 {
		for _ in 1..10000 {
			x = x * 1.001;
		}
	}
	x
}

async fn print_dot(){
	println!(".");
}

async fn print_plus(){
	plusfunc().await;
}

async fn print_minus() {
	wait();
	println!("-");
}

async fn plusfunc(){
	wait();
	println!("+");
}

async fn async_main() {
	let f1 = print_plus();
	let f2 = print_minus();
	let f3 = print_dot();
	println!("Hello");
	futures::join!(f1, f2, f3);
}

fn main(){
	block_on(async_main());
}

Rust スレッド間通信、排他制御

並列で実行されているスレッド間で情報を受け渡す
グローバルなstatic変数を使うか、チャンネルを使う

チャンネルではメインスレッドとスレッドとの間で特定の型の値を受け渡す通信機構を提供する
let (tx, rx) = mpsc::channel();
tx.send(count).unwrap();

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

fn main(){
	let (tx, rx) = mpsc::channel();

	let th = thread::spawn(move || {
		let mut count = 0;
		for _i in 1..11 {
			count = count + 1;
			tx.send(count).unwrap();
		}
	});

	let mut cnt = 0;
	for _i in 1..11 {
		cnt = cnt + 1;
		thread::sleep(Duration::from_millis(100));
	}

	th.join().unwrap();
	let val = rx.recv().unwrap();
	println!("カウンタ={}", cnt + val);
	println!("プログラム終了");
}

### 排他制御
複数のスレッドが同じ変数にアクセスすることを避ける方法
std::syncにあるっミューテックスという方法を使って、他のスレッドが変数の値を変更しないようにする
let counter = Arc::new(Mutex::new(0));

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

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

	let counter1 = Arc::clone(&counter);
	let th1 = thread::spawn(mmove || {
		for _i in 1..11 {
			print("+");
			let mut num = counter1.lock().unwrap();
			*num += 1;
			thread::sleep(Duration::from_millis(100));
		}
	});

	let counter2 = Arc::clone(&counter);
	let th2 = thread::spawn(move || {
		for _i in 1..11 {
			let mut num = counter2.lock().unwrap();
			*num += 1;
			print!("-");
			thread::sleep(Duration::from_millis(100));
		}
	});

	th1.join().unwrap();
	th2.join().unwrap();
	println!("\ncounter={:?}", counter);
}

アトミック

use std::thread;
use std::time::Duration;
use std::sync::atomic::{self, AtomicU32, Ordering};

static COUNTER: AtopmicU32 = AtomicU32::new(0);

fn count_up(){
	COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
}
fn get_count() -> u32 {
	return COUNTER.load(Ordering::SeqCst);
}


fn main(){
	let th1 = thread::spawn(mmove || {
		for _i in 1..11 {
			print("+");
			count_up();
			thread::sleep(Duration::from_millis(100));
		}
	});

	let th2 = thread::spawn(move || {
		for _i in 1..11 {
			print!("-");
			count_up();
			thread::sleep(Duration::from_millis(100));
		}
	});

	th1.join().unwrap();
	th2.join().unwrap();
	println!("\ncounter={}", get_count());
}

Rust 並列処理

Rustには1つのプロセスで複数のスレッドを実行するメカニズムも備わっている。そのため、同時に複数のことを行うことができる。

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

fn printch(c: char){
	println!("スレッド{}スタート", c);
	for _i in 1..10 {
		print!("{}", c);
		thread::sleep(Duraion::from_millis(100));
	}
	println!("スレッド{}終了", c);
}

fn main(){
	let th1 = thread::spawn(|| printch('A'));
	let th2 = thread::spawn(|| printch('B'));
	let th3 = thread::spawn(|| printch('C'));

	th1.join().unwrap();
	th2.join().unwrap();
	th3.join().unwrap();
	println!("プログラム終了");
}

### クロージャー化
スレッドを起動するためには無名関数は次のように呼び出す
thread::spawn(|| {
});

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

fn main(){
	let th1 = thread::spawn(|| {
		println!("スレッド1スタート");
		for _i in 1..10 {
			print!("A");
			thread::sleep(Duration::from_millis(100));
		}
		println!("スレッド1終了");
	});
	let th2 = thread::spawn(|| {
		print!("スレッド2スタート");
		for _i in 1..10 {
			print!("B");
			thread::sleep(Duration::from_millis(100));
		}
		println!("スレッド2終了");

	});

	th1.join().unwrap();
	th2.join().unwrap();
	println!("プログラム終了");
}
use std::thread;
use std::time::Duration;

fn main(){
	let func = |c| {
		for _i in 1..10 {
			print!("{}", c);
			thread::sleep(Duration::fromm_millis(100));
		}
	}

	let th1 = thread::spawn(move || func("A"));
	let th2 = thread::spawn(move || func("B"));

	th1.join().unwrap();
	th2.join().unwrap();
	println!("プログラム終了");
}

Rust モジュール

fn three_times(x: i32) -> i32 {
	x * 3
}

fn main() {
	
	for i in 1..4 {
		println!("{}の3倍={}", i, three_times(i));
	}
}

//modsample/src/myutil.rs

pub fn three_times(x: i32) -> i32 {
	x * 3
}
mod myutil;

fn main() {
	
	for i in 1..4 {
		println!("{}の3倍={}", i, myutil ::three_times(i));
	}
}

### ライブラリ
独立したライブラリの作成
$ cargo new mysamplelib –lib

pub fn half(x: i32) -> i32 {
	x / 2
}
use mysamplelib;

fn main() {
	let x = 12;
	let y = mysamplelib::half(x);
	println!("{}の半分は{}", x, y);
}
[package]
name="testmylib"
version = "0.1.0"
authors = ["notes"]
edition = ""

reference/manifest.html

[dependencies]
mysamplelib = {path = "../mysamplelib"}

Rust ライブラリ

Rustでも標準で誰もが使うものが用意されている。ライブラリに相当するものをクレート(crate)と呼ぶことがある
基本的なstdにはプリミティブなデータ型やモジュール、マクロなどが定義されている
crates.ioにたくさんのパッケージがある

let f:f64 = 3.45;
let val = f.sqrt();

use std::f64;

fn main() {
	let f:f64 = 3.45;
	println!("{}の平方根={:?}", f, f.sqrt());
}
fn main() {
	let s = "hello, dogs";
	println!("{:?}", s.to_uppercase());
}

乱数はRngというトレイトを使うことができる

use rand::Rng;

fn main() {
	let mut r = rand::thread_rng();
	for _i in 1..6 {
		println!("{}", r.gen_range(1, 11));
	}
}

### クレートを使うプロジェクト
クレートの最新バージョンを調べる
$ cargo search rand
Updating crates.io index
rand = “0.8.5” # Random number generators and other randomness functionality.
tinyrand = “0.5.0” # Lightweight RNG specification and several ultrafast implementations in Rust.
bevy_rand = “0.1.0” # A plugin to integrate rand for ECS optimised RNG for the Bevy game engine.
random_derive = “0.0.0” # Procedurally defined macro for automatically deriving rand::Rand for structs and enums
faker_rand = “0.1.1” # Fake data generators for lorem ipsum, names, emails, and more
rand_derive2 = “0.1.21” # Generate customizable random types with the rand crate
fake-rand-test = “0.0.0” # Random number generators and other randomness functionality.
ndarray-rand = “0.14.0” # Constructors for randomized arrays. `rand` integration for `ndarray`.
rand_derive = “0.5.0” # `#[derive(Rand)]` macro (deprecated).
rand_core = “0.6.4” # Core random number generator traits and tools for implementation.
… and 1126 crates more (use –limit N to see more)

$ cargo new random3 –bin
Created binary (application) `random3` package

実数の数値計算
abs(), acos(), asin(), atan(), ceil(), copisign(), cos(), exp(), exp2(), floor(), fract(), ln(), log(), log10(), log2(), mul_add(), powf(), powi(), round(), signum(), sin(), sqrt(), tan(), trunc()

use std::f64;

fn main() {
	let f:f64 = 3.45;
	println!("{:?}", f.fract());
}

文字列の操作
find(), matches(), parse(), repeat(), to_lowercase(), to_uppercase(), trim(), trim_end(), trim_start()

乱数の生成
gen(), gen_range(), gen_bool(), gen_ratio(2, 3)

use rand::{thread_rng, Rng};

fn main() {
	let mut rng = thread_rng();

	for _ in 0..11 {
		let x: u16 = rng.gen();
		print!("{} ", x);
	}
}
use rand::{thread_rng, Rng};

fn main() {
	let mut rng = thread_rng();

	for _ in 0..11 {
		let x: u16 = rng.gen_range(0, 3);
		print!("{} ", x);
	}
}

### 日付日時
Date, DateTime, Duration

use chrono::{Utc, Local, DateTime};
use chrono::{Datelike, Timelike};

fn main() {
	let utc: DateTime<Utc> = Utc::now();
	println!("{}", utc);

	let local: DateTime<Local> = Local::now();
	println!("{}", local);

	println!("{}/{}/{}", local.year(), local.month(), local.day());
	println!("{:02}:{:02}:{:02}",
		local.hour(), local.minute(), local.second());
}
use std::thread;
use std::time::Duration;

fn main() {
	println!("3秒待ちます。");
	thread::sleep(Duration::from_secs(3));
	println!("3秒待ちました");
}

Rust マクロ

マクロは一定の手順をまとめて呼び出せるようにしたもの
print!(), println!(), format!(), vec!()のように最後に!が付けられている

macro_rules! name {
(var: disanator) => {rep}
}

disanatorは一致されるものの種類
disanatorに指定できる指定子
block, expr, ident, itemm, meta, pat, path, stmt, tt, ty

macro_rules! twice {
	($x:expr) => {
		$x * 2
	}
}

fn main() {
	let n = 8;
	println!("{}の2倍は={}", n, twice!(n));
}
struct Point {
	x: i32,
	y: i32,
}

macro_rules! print_type {
	($t:ty) => (println!("{:?}", stringify!($t)))
}

fn main() {
	print_type!(i32);
	print_type!(i64);
	print_type!(usize);
	print_type!(Point);
}

Rust トレイト

トレイト(trait)は、構造体にルールを定義する

struct Dog {
	name: String,
	age: i32,
}

struct Cat {
	name: String,
	age: i32,
}

trait Cry {
	fn cry(&self);
}

impl Cry for Dog {
	fn cry(&self) {
		println!("わんわん");
	}
}

impl Cry for Cat {
	fn cry(&self) {
		println!("にゃお");
	}
}

fn main() {
	let d = Dog {name: String::from("ポチ"), age: 6};
	println!("{}({})", d.name, d.age);
	d.cry();
	let c = Cat {name:String::from("タマ"), age:4};
	println!("{}({})", c.name, c.age);
	c.cry();
}

### ジェネリックなメソッド

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

trait Printdata { fn print(&self); }
impl<T, U> Printdata for Point<T, U>
	where T: std::fmt::Display, U: std::fmt::Display {
		fn print(self: &Point<T, U>){
			println!("({}, {})", self.x, self.y);
		}
	}

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

	p1.print();
	println!("p2.X={}, p2.y={}", p2.x, p2.y);
}

所有権とトレイト

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


fn main(){
	let p = Point {x: 12, y:25};
	print(p);
	println!("({}, {})", p.x, p.y);
}

fn print(p:Point) {
	println!("({}, {})", p.x, p.y);
}

### clone()

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

impl Clone for Point {
	fn clone(&self) -> Self {
		Point {
			x: self.x.clone(),
			y: self.y.clone(),
		}
	}
}


fn main(){
	let p = Point {x: 12, y:25};
	print(p.clone());
	println!("({}, {})", p.x, p.y);
}

fn print(p:Point) {
	println!("({}, {})", p.x, p.y);
}

Rust メソッド

メソッドは値に作用する一種の関数
原則的に特定の値を操作する一連のコードなので、特定の値と関連ずけする必要がある

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

impl Point {
	fn print(&self) {
		println!("({}, {})", self.x, self.y);
	}
}

fn main() {
	let p = Point {x:10, y:20};
	p.print();
}

### 引数と戻り値を伴うメソッド

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

impl Point {
	fn print(&self) {
		println!("({}, {})", self.x, self.y);
	}

	fn mult(&self, n:i32) -> (i32, i32){
		let a = self.x * n;
		let b = self.y * n;
		(a, b)
	}
}

fn main() {
	let p = Point {x:10, y:20};
	p.print();

	let v = p.mult(2);
	println!("{:?}", v);
	let p2 = Point {x:(v.0), y:(v.1)};
	p2.print();
}

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