let nums = vec![1, 3, 5, 7, 9, 11]; let n = nums.iter().position(|n| *n == 5).unwrap(); println!("{}", n);
2
なるほど〜 これをダイクストラ法で使用します。
随机应变 ABCD: Always Be Coding and … : хороший
let nums = vec![1, 3, 5, 7, 9, 11]; let n = nums.iter().position(|n| *n == 5).unwrap(); println!("{}", n);
2
なるほど〜 これをダイクストラ法で使用します。
最短距離を探すアルゴリズム
fn bellman_ford(edges: Vec<[usize; 3]>, num_v: usize) -> Vec<usize>{ let inf = 999; let mut dist = Vec::new(); for _ in 0..num_v { dist.push(inf); } dist[0] = 0; let mut changed = true; while changed == true { changed = false; for edge in &edges { if dist[edge[1]] > dist[edge[0]] + edge[2] { dist[edge[1]] = dist[edge[0]] + edge[2]; changed = true; } } } return dist; } fn main() { let edges = vec![[0, 1, 4], [0, 2, 3], [1, 2, 1], [1, 3, 1], [1, 4, 5], [2, 5, 2], [4, 6, 2], [5, 4, 1], [5, 6, 4]]; let dist = bellman_ford(edges, 7); println!("{:?}", dist); }
Compiling rust v0.1.0 (/home/vagrant/dev/algorithm/rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
Running `target/debug/rust`
[0, 4, 3, 5, 6, 5, 8]
いまいちよーわからん…
import socket host = socket.gethostname() print(host) ip = socket.gethostbyname(host) print(ip)
$ python3 test.py
vagrant
127.0.1.1
$ pip3 install netaddr
from netaddr import * ip = IPAddress('127.0.1.1') print(ip.version) print(IPAddress('127.0.1.1').ipv6())
rustの場合、is_ipv4でipv4の判定、is_ipv6判定などができる。
なるほど、ipv4, v6は深掘りする必要がありそう。
ncコマンドの場合、”-u”がUDPを指定している
$ nc -u -l 8888
$ echo “hoge” | nc -u 127.0.0.1 8888
use std::net::UdpSocket; fn main() -> std::io::Result<()> { { let socket = UdpSocket::bind("127.0.0.1:8080")?; let mut buf = [0; 100]; let (amt, src) = socket.recv_from(&mut buf)?; let buf = &mut buf[..amt]; buf.reverse(); socket.send_to(buf, &src)?; } Ok(()) }
$ echo “hoge” | nc -u 127.0.0.1 8080
egoh
UDPのbindはできるけど、レスポンスが何かおかしい…
use std::net::UdpSocket; use std::thread; use std::str; fn main() -> std::io::Result<()> { { let socket = UdpSocket::bind("127.0.0.1:8080")?; let mut buf = [0; 2048]; loop { match socket.recv_from(&mut buf) { Ok((buf_size, src_addr)) => { thread::spawn(move || { let buf = &mut buf[..buf_size]; let req_msg = str::from_utf8(&buf).unwrap(); println!("request message: {:?}", req_msg); }); }, Err(e) => { println!("couldn't receive request: {:?}", e); } } } } }
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.63s
Running `target/debug/app`
request message: “hoge\n”
なるほど、TCPだけでなく、UDPも割と簡単にできるのね。。音声、動画streamingはUDPが優れているが…
Node.jsとGolangを合体させたもの
膨大なリクエストをシングルスレッド&イベントループ&非同期I/Oで効率よく処理するランタイム(ライブラリ)
tokioではOSではなくランタイムがタスクのスケジューリングを行う。タスク生成はtokio::spawnを呼び出す
use std::time::Duration; #[tokio::main] async fn main() { tokio::task::spawn(async { tokio::time::sleep(Duration::from_secs(2)).await; println!("Done"); }); std::thread::sleep(Duration::from_secs(3)); println!("wake up"); }
シングルスレッド
use std::time::Duration; #[tokio::main(flavor="current_thread")] async fn main() { tokio::task::spawn(async { tokio::time::sleep(Duration::from_secs(2)).await; println!("Done"); }); std::thread::sleep(Duration::from_secs(3)); println!("wake up"); }
use std::time::Duration; #[tokio::main(flavor="multi_thread", worker_threads = 1)] async fn main() { let cpus = num_cpus::get(); println!("logical cores: {}", cpus); tokio::task::spawn(async move { println!("task 1 started.."); tokio::time::sleep(Duration::from_secs(3)).await; println!("task 1 wake up"); }); tokio::task::spawn(async move { println!("task 2 started.."); tokio::time::sleep(Duration::from_secs(1)).await; println!("task 2 wake up"); }); tokio::time::sleep(Duration::from_secs(5)).await; println!("wake up"); }
task 1 started..
task 2 started..
task 2 wake up
task 1 wake up
wake up
use std::time::Duration; use futures::{stream::FuturesUnordered, StreamExt}; use std::thread; #[tokio::main(flavor="multi_thread", worker_threads = 1)] async fn main() { // console_subscriber::init(); let mut tasks = FuturesUnordered::new(); let h1 = tokio::spawn(async move { thread::sleep(Duration::from_secs(10)).await; println!("0 wake up"); }); tasks.push(h1); println!("0 started..."); for i in 1..100 { let h2 = tokio::spawn(async move { tokio::time::sleep(Duration::from_secs(1)).await; println!("{i} woke up!"); }); tasks.push(h2); println!("{i} ..."); } while let Some(item) = tasks.next().await { let () = item.unwrap(); } println!("Done"); }
Postではなく、Getでデータを渡したいときに、パスパラメータを使用する
route(“/withdrawal/{param}” でパスパラメータを取得できる。以前は、route(“/withdrawal/:param” だったので変わったみたい。
html
<button onclick="location.href='./withdrawal/eyJ2ZXJzaW9uIjoiMC4xLjAiLCJ0aW1lIjoiMjAyNS0wMi0xNVQwNzoxNzo0Mi4xMDU3Njk4NDNaIiwic2VuZGVyIjoiMDQxMGY4NzQyOWU4OTQ5OGU5MjhkMDBiNmE2MTg2ZmRjOWNjYmRlMmNhNTVkNTc0NmYwZTFiZjhmMWExZmJkYjc'">ボタン</button>
axum
let app = Router::new() .route("/", get(handle_index)) .route("/withdrawal/{param}", get(handle_withdrawal)) // async fn handle_withdrawal(axum::extract::Path(param): axum::extract::Path<String>) { println!("{}", param); }
なるほど〜
$ cargo install wasm-pack
$ cargo new –lib hello-wasm
$ tree
.
└── hello-wasm
├── Cargo.toml
└── src
└── lib.rs
2 directories, 2 files
src/lib.rs
use wasm_bindgen::prelude::*; #[wasm_bindgen] extern { pub fn alert(s: &str); } #[wasm_bindgen] pub fn greet(name: &str){ alert(&format!("Hello, {}!", name)); }
Cargo.toml
[lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen= "0.2"
build
$ wasm-pack build –target web
index.html
<body> <script type="module"> import init, { greet } from "./pkg/hello_wasm.js"; init().then(() => { greet("WebAssembly"); }); </script> </body>
なるほど、WebAssemblyか、次々に新しい技術が出てきますね…
参考)
https://developer.mozilla.org/ja/docs/WebAssembly/Guides/Rust_to_Wasm
$ mkdir add
$ cd add
Cargo.toml
[workspace] members = [ "adder", ]
$ cargo new –bin adder
$ tree
.
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── Cargo.toml
$ cargo new add-one –lib
$ tree
.
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
├── add-one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── Cargo.toml
pub fn add_one(x: i32) -> i32 { x + 1 }
adder/Cargo.toml
[dependencies] add-one = {path = "../add-one"}
adder/src/main.rs
extern crate add_one; fn main() { let num = 10; println!("Hello, world!{} plus one is {}!", num, add_one::add_one(num)); }
$ cargo run
Compiling add-one v0.1.0 (/home/vagrant/dev/rust/add/add-one)
Compiling adder v0.1.0 (/home/vagrant/dev/rust/add/adder)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.15s
Running `target/debug/adder`
Hello, world!10 plus one is 11!
なるほど、ワークスペースを使ってパッケージ管理してるのか!
プリエンティブマルチタスク: OSにより実行を制御する
協調的マルチタスク: コンテキストの切り替え、スレッドの置き換えはできる
コールチン: 協調的マルチタスクを制御できる
Futureオブジェクト: 処理が終わったらコールバック、awaitは実行完了まで待つ
use std::{thread, time}; #[tokio::main] async fn main(){ let handle = tokio::spawn(async { thread::sleep(time::Duration::from_millis(1000)); println!("1 sec elapsed"); }); let order = "beef burger".to_string(); order_burger(order).await; play_game().await; } async fn order_burger(order: String) -> Result<String, Box<dyn std::error::Error>> { match order { ref val if *val == "beef burger".to_string() => thread::sleep(time::Duration::from_millis(200)), ref val if *val == "cake".to_string() => thread::sleep(time::Duration::from_millis(300)), _ => println!("Please order!"), } println!("Order received {}", order); Ok(order) } async fn play_game() { println!("I am playing game"); }
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.60s
Running `target/debug/app`
Order received beef burger
I am playing game
1 sec elapsed
asyncの関数をawaitで実行した場合は、その次の関数は実行完了まで実行されない。
別のスレッドを立てた場合は、並列で処理がされる。
なるほど、async処理をawaitする意味が何となくわかった。
https://docs.rs/websockets/latest/websockets/struct.WebSocket.html
websockets=”0.3.0″
use websockets::WebSocket; use websockets::Frame; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut ws = WebSocket::connect("wss://echo.websocket.org/").await?; ws.send_text("foo".to_string()).await?; ws.receive().await?; if let Frame::Text { payload: received_msg, .. } = ws.receive().await? { println!("{}", received_msg); } ws.close(None).await?; Ok(()) }
Compiling app v0.1.0 (/home/vagrant/dev/rust/app)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.00s
Running `target/debug/app`
foo
なるほどー