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
なるほどー