【Rust】ファイルの上書き処理

File::createとwrite_allで元のデータは上書かれる。
例えば、元データが4行で、上書きデータが2行だった場合でも、上書き後は2行になる。

{"family":"john","first":"fox"}
{"family":"adam","first":"can"}
{"family":"john","first":"fox"}
{"family":"adam","first":"can"}
use serde::{Serialize, Deserialize};
use std::path::Path;
use std::fs::{File};
use std::io::{Write};

#[derive(Serialize, Deserialize, Clone, Debug)]
struct Name {
    family: String,
    first: String,
}

#[tokio::main]
async fn main() {

    let name1 = Name {family:"yamada".to_string(), first: "taro".to_string()};
    let name2 = Name {family:"sato".to_string(), first: "kazuki".to_string()};

    let mut vect: Vec<Name> = Vec::new();
    vect.push(name1);
    vect.push(name2);

    let file_path = format!("./data/names.txt");
    let mut file = File::create(file_path.clone()).unwrap();
    for name in vect {
        let serialized: Vec<u8> = serde_json::to_vec(&name).unwrap();
        file.write_all(&serialized).expect("write failed");
        file.write_all(b"\n").expect("write failed");
    }
    println!("done");

}  
{"family":"yamada","first":"taro"}
{"family":"sato","first":"kazuki"}

なるほどね!

【ubuntu2204】error: linking with `cc` failed: exit status: 1

$ cargo run

error: linking with `cc` failed: exit status: 1
|
= note: LC_ALL=”C” PATH=”/home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/ubuntu/.local/bin:/home/ubuntu/.cargo/bin:/usr/local/sbin:
//

“-nodefaultlibs”
= note: some arguments are omitted. use `–verbose` to show all linker arguments
= note: collect2: fatal error: ld terminated with signal 9 [Killed]
compilation terminated.

最後に、「collect2: fatal error: ld terminated with signal 9 [Killed]」と表示されていますが、これが、メモリ不足のエラーの模様
https://stackoverflow.com/questions/46259776/collect2-fatal-error-ld-terminated-with-signal-9-killed

swapファイルを作成すると、エラーが消えます。
$ sudo fallocate -l 1G /swapfile
$ ls -lh /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo swapon –show
$ free -h

【Rust】日にち、時間差の計算

Unix Timeに変換して計算する。UnixTimeは秒単位のため、1日の場合は、60 * 60 * 24 = 86400となる。

    let utc_datetime: DateTime<Utc> = DateTime::parse_from_rfc3339("2025-01-01T00:00:00Z").unwrap().into();
    println!("{}", utc_datetime.timestamp());
    let utc_datetime2: DateTime<Utc> = DateTime::parse_from_rfc3339("2025-01-02T00:00:00Z").unwrap().into();
    println!("{}", utc_datetime2.timestamp());

    // 86400
    println!("{}", utc_datetime2.timestamp() - utc_datetime.timestamp());

Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.24s
Running `target/debug/app`
1735689600
1735776000
86400

経過時間は、unixtimeの差を86400で割れば日数となるので、

    let base_date = "2025-01-01T00:00:00Z".to_string();
    let utc_datetime: DateTime<Utc> = DateTime::parse_from_rfc3339(&base_date).unwrap().into();
    let utc_datetime2: DateTime<Utc> = Utc::now();
    println!("{}", utc_datetime2.timestamp());
    println!("{}", (utc_datetime2.timestamp() - utc_datetime.timestamp()) / 86400);

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.67s
Running `target/debug/app`
1741587141
68

1月1日から、68日経過していることになる。

【Rust】Vectorのstructを1行ずつファイルに書き込む

async fn handle_index()-> Response {
    let mut name_list: Vec<Name> = Vec::new();
    let name1 = Name { family: "tanaka".to_string(), first: "taro".to_string(), age: 12};
    let name2 = Name { family: "yamada".to_string(), first: "koji".to_string(), age: 13};
    let name3 = Name { family: "okamoto".to_string(), first: "ai".to_string(), age: 14};
    name_list.push(name1);
    name_list.push(name2);
    name_list.push(name3);
    let name_list_serialized = serde_json::json!(&name_list);

    let mut post_url = format!("http://192.168.33.10:3000/fetch");
    let client = reqwest::Client::new();
    let resp = client.post(post_url)
        .header(reqwest::header::CONTENT_TYPE, "application/json")
        .json(&name_list_serialized)
        .send()
        .await
        .unwrap();
    // println!("{:?}", resp);

    "All good".into_response()
}

async fn handle_fetch(extract::Json(names): extract::Json<Vec<Name>>)-> Response {

    println!("get names: {:?}", names);

    let file_path = format!("./data/names.txt");
    if !Path::new(&file_path.clone()).exists() {
        let mut file = File::create(file_path.clone()).unwrap();
        for name in names {
            let serialized: Vec<u8> = serde_json::to_vec(&name).unwrap();
            file.write_all(&serialized).expect("write failed");
            file.write_all(b"\n").expect("write failed");
        }
        println!("done");
    } else {
        println!("file exist");
    }
    "All good".into_response()
}

names.txt
{“family”:”tanaka”,”first”:”taro”,”age”:12}
{“family”:”yamada”,”first”:”koji”,”age”:13}
{“family”:”okamoto”,”first”:”ai”,”age”:14}

うん、期待通りです。

【Rust】[i32; n]からStringへの変換と、String(chars)から[i32; n]への変換

[i32; 10]からStringへの変換

    let mut bf = BloomFilter { filter: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]};
    bf.set_v("hello world".to_string());
    println!("{:?}", bf.filter);

    let mut bloom_str = String::new();
    for i in bf.filter {
        bloom_str = format!("{}{}", bloom_str, i);
    }
    println!("{}", bloom_str);

String(chars)から[i32; n]への変換

    let str = "2201211222".to_string();
    let mut filter:[i32;10] = [0,0,0,0,0,0,0,0,0,0];
    for (i,c) in str.chars().enumerate() {
        filter[i] = (c.to_string()).parse::<i32>().unwrap();
    }
    println!("{:?}", filter);

[2, 2, 0, 1, 2, 1, 1, 2, 2, 2]

websocketで、send_textはあるけど、send_binary, sendしかなく、配列の送り方が不明なので、[i32; n]を文字列に変換して、受け取った側で、[i32; n]に戻すという処理にしている。
うーん、 なんか

【Rust】WebSocketクライアント側のエラーハンドリング

websocketで通信して、connection errorや、通信内容の処理でのエラーハンドリング
以下のように書くと、接続先のURLにミスがあった場合もerrorを返してくれる。

#[tokio::main]
async fn main() {
    let url = format!("wss://echo.websocket.org/");
    // let url = format!("wss://echo.aaaaaaa.org/");
    let res = web_socket(url).await;
    match res {
        Ok(_) => {
            println!("wsに成功しました!");
        }
        Err(error) => {
            println!("wsに失敗");
            println!("{}", error);
        }
    }
}  

async fn web_socket(url: String) -> Result<(), Box<dyn std::error::Error>> {
    
    let mut ws = WebSocket::connect(&url).await?;
    ws.send_text("foo".to_string()).await?;
    ws.receive().await?;
    if let Frame::Text { payload: received_msg, .. } =  ws.receive().await? {
        println!("{}", received_msg);
        if received_msg != "hoge" {
            let error = "メッセージの照合に失敗しました。".to_string();
            return Err(error.into());
        }
    }
    ws.close(None).await?;
    Ok(())
}

– connectionエラー
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.17s
Running `target/debug/app`
wsに失敗
could not parse into SocketAddrs

– ソケット通信での内容でのエラーを明示的にエラーとして知らせる
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.81s
Running `target/debug/app`
foo
wsに失敗
メッセージの照合に失敗しました。

– 成功時
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.58s
Running `target/debug/app`
foo
wsに成功しました!

以下のような書き方はできない。

let mut ws = WebSocket::connect(&url).await?;
match ws {
    Ok(_) => {
        println!("wsに成功しました!");
    }
    Err(error) => {
        println!("wsに失敗");
        println!("{}", error);
    }
}

なるほど、これは面白い。

【Rust】reqwestのresponseでstatusコードによって切り分ける

error_for_status() で、エラーレスポンスの場合を取得できる。
https://docs.rs/reqwest/latest/reqwest/struct.Response.html
200の場合は通過する。

pub async fn handle_health() -> Response {
    (StatusCode::OK, format!("I'm ACTIVE")).into_response()
    // (StatusCode::BAD_REQUEST, format!("Something wrong happened")).into_response()
}

async fn handle_post_test()-> Response {
    let res = reqwest::get("http://192.168.33.10:3000/health").await;
    match res.unwrap().error_for_status() {
        Ok(_res) => {
            println!("health check is OK");
        },
        Err(_err) => {
            println!("got bad request response. something wrong");
        }
    }
    //
}

なるほど〜

レスポンスで、statusコードをStatusCode::OKと返却しない場合でも、.error_for_status()は通過する。

// OK
(StatusCode::OK, format!(“I’m ACTIVE”)).into_response()
// OK
“All good”.into_response()
// Err
(StatusCode::BAD_REQUEST, format!(“Something wrong happened”)).into_response()

【Rust】【アルゴリズム】くじ引き

4回くじを引くという条件から、nパターンの4回分を全通り試して、一致する組み合わせを探している。
全通りを探す場合、ループの中でループをするという書き方が多い。

static MAX_N: usize = 50;

fn main() {
    let mut n: i32;
    let mut m: i32;
    let mut k: Vec<i32> = Vec::new();

    println!("紙の枚数 n を入力してください。");
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    let n = line.trim().parse::<i32>().unwrap();
    println!("期待する数字の和 m を入力してください。");
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    let m = line.trim().parse::<i32>().unwrap();

    println!("紙に書かれている数字をそれぞれ入力してください。");
    for i in 0..n {
        println!("{}番目の数字:", i + 1);
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).ok();
        let n = line.trim().parse::<i32>().unwrap();
        k.push(n);
    }

    let mut flg = false;

    for a in 0..n {
        for b in 0..n {
            for c in 0..n {
                for d in 0..n {
                    if k[a as usize] + k[b as usize] + k + k[d as usize] == m {
                        flg = true;
                        println!("発見! 組み合わせは{},{},{},{}", k[a as usize], k[b as usize], k, k[d as usize]);
                    }
                }
            }
        }
    }

    if !flg {
        println!("そのような組み合わせはありません。");
    }
}

紙の枚数 n を入力してください。
3
期待する数字の和 m を入力してください。
10
紙に書かれている数字をそれぞれ入力してください。
1番目の数字:
3
2番目の数字:
3
3番目の数字:
2
発見! 組み合わせは3,3,2,2
発見! 組み合わせは3,3,2,2
発見! 組み合わせは3,2,3,2
発見! 組み合わせは3,2,3,2
発見! 組み合わせは3,2,2,3
発見! 組み合わせは3,2,2,3
発見! 組み合わせは3,3,2,2
発見! 組み合わせは3,3,2,2
発見! 組み合わせは3,2,3,2
発見! 組み合わせは3,2,3,2
発見! 組み合わせは3,2,2,3
発見! 組み合わせは3,2,2,3
発見! 組み合わせは2,3,3,2
発見! 組み合わせは2,3,3,2
発見! 組み合わせは2,3,2,3
発見! 組み合わせは2,3,2,3
発見! 組み合わせは2,3,3,2
発見! 組み合わせは2,3,3,2
発見! 組み合わせは2,3,2,3
発見! 組み合わせは2,3,2,3
発見! 組み合わせは2,2,3,3
発見! 組み合わせは2,2,3,3
発見! 組み合わせは2,2,3,3
発見! 組み合わせは2,2,3,3

【Rust】mutexのvectorから指定した複数の値を削除する

普通のvectorから1つだけ削除

    let target = 2;
    let mut vec = vec![1, 2, 3, 4, 5];
    if let Some(remove_index) = vec.iter().position(|x| *x == target){
        vec.remove(remove_index);
    }
    println!("{:?}", vec);

[1, 3, 4, 5]

vectorから複数削除する

    let targets = [2, 4];
    let mut vec = vec![1, 2, 3, 4, 5];
    for target in targets {
        if let Some(remove_index) = vec.iter().position(|x| *x == target){
            vec.remove(remove_index);
        }
    }
    println!("{:?}", vec);

[1, 3, 5]

vectorの中身が構造体の時
=> 基本同じ処理

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
struct Person {
    last: String,
    first: String,
    age: i32
}
//
    let mut vec: Vec<Person> = Vec::new();
    let person1 = Person{last:"yamada".to_string(), first:"taro".to_string(), age: 20};
    let person2 = Person{last:"yoshida".to_string(), first:"akira".to_string(), age: 15};
    let person3 = Person{last:"takahashi".to_string(), first:"kazumi".to_string(), age: 21};
    let person4 = Person{last:"ichiba".to_string(), first:"kumi".to_string(), age: 22};
    let person5 = Person{last:"okamoto".to_string(), first:"hajime".to_string(), age: 17};
    vec.push(person1.clone());
    vec.push(person2.clone());
    vec.push(person3.clone());
    vec.push(person4.clone());
    vec.push(person5.clone());
    

    let mut engineers:Vec<Person> = Vec::new();
    engineers.push(person1);
    engineers.push(person2);

    for engineer in engineers {
        if let Some(remove_index) = vec.iter().position(|x| *x == engineer){
            vec.remove(remove_index);
        }
    }
    println!("{:?}", vec);

[Person { last: “takahashi”, first: “kazumi”, age: 21 }, Person { last: “ichiba”, first: “kumi”, age: 22 }, Person { last: “okamoto”, first: “hajime”, age: 17 }]

### mutexのvectorの場合
=> うまくいかない

static VECT: Lazy<Mutex<Vec<Person>>> = Lazy::new(|| Mutex::new(vec![]));

#[tokio::main]
async fn main() {

    let mut vec: Vec<Person> = Vec::new();
    let person1 = Person{last:"yamada".to_string(), first:"taro".to_string(), age: 20};
    let person2 = Person{last:"yoshida".to_string(), first:"akira".to_string(), age: 15};
    let person3 = Person{last:"takahashi".to_string(), first:"kazumi".to_string(), age: 21};
    let person4 = Person{last:"ichiba".to_string(), first:"kumi".to_string(), age: 22};
    let person5 = Person{last:"okamoto".to_string(), first:"hajime".to_string(), age: 17};
    VECT.lock().unwrap().push(person1.clone());
    VECT.lock().unwrap().push(person2.clone());
    VECT.lock().unwrap().push(person3.clone());
    VECT.lock().unwrap().push(person4.clone());
    VECT.lock().unwrap().push(person5.clone());
    

    let mut engineers:Vec<Person> = Vec::new();
    engineers.push(person1);
    engineers.push(person2);

    for engineer in engineers {
        if let Some(remove_index) = VECT.lock().unwrap().iter().position(|x| *x == engineer){
            VECT.lock().unwrap().remove(remove_index);
        }
    }
    println!("{:?}", VECT.lock().unwrap());
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.94s
Running `target/debug/app`

処理が止まったままになる…

ちょっとコードが冗長になるが、別の関数に切り出して、削除後のデータを再度空にしたmutexに入れるという処理を行うと上手くいく。

#[tokio::main]
async fn main() {
    // mutex vectorの準備
    let mut vec: Vec<Person> = Vec::new();
    let person1 = Person{last:"yamada".to_string(), first:"taro".to_string(), age: 20};
    let person2 = Person{last:"yoshida".to_string(), first:"akira".to_string(), age: 15};
    let person3 = Person{last:"takahashi".to_string(), first:"kazumi".to_string(), age: 21};
    let person4 = Person{last:"ichiba".to_string(), first:"kumi".to_string(), age: 22};
    let person5 = Person{last:"okamoto".to_string(), first:"hajime".to_string(), age: 17};
    VECT.lock().unwrap().push(person1.clone());
    VECT.lock().unwrap().push(person2.clone());
    VECT.lock().unwrap().push(person3.clone());
    VECT.lock().unwrap().push(person4.clone());
    VECT.lock().unwrap().push(person5.clone());
    
    println!("{:?}", VECT.lock().unwrap());

    // mutex vectorから削除したい値
    let mut engineers:Vec<Person> = Vec::new();
    engineers.push(person1);
    engineers.push(person2);

    let objs = processing_mutex_vector(engineers).await;

    // 一度全て削除し、残したいデータを挿入する
    VECT.lock().unwrap().clear();
    for obj in objs {
        VECT.lock().unwrap().push(obj);
    }
    println!("{:?}", VECT.lock().unwrap());

}

async fn processing_mutex_vector(engineers:Vec<Person>) -> Vec<Person> {

    let mut binding = VECT.lock().unwrap();
    let objs = binding.deref_mut();

    for engineer in engineers {
        if let Some(remove_index) = objs.iter().position(|x| *x == engineer){
            objs.remove(remove_index);
        }
    }
    return objs.to_vec();
}

[Person { last: “yamada”, first: “taro”, age: 20 }, Person { last: “yoshida”, first: “akira”, age: 15 }, Person { last: “takahashi”, first: “kazumi”, age: 21 }, Person { last: “ichiba”, first: “kumi”, age: 22 }, Person { last: “okamoto”, first: “hajime”, age: 17 }]
[Person { last: “takahashi”, first: “kazumi”, age: 21 }, Person { last: “ichiba”, first: “kumi”, age: 22 }, Person { last: “okamoto”, first: “hajime”, age: 17 }]

【Rust】hex::encodeとhex::decode

hex::encodeした値をhex::decodeした場合、元のStringを .to_owned().into_bytes() としないといけない。

pub static TEST_STRING : &'static str = "hogehoge";

#[tokio::main]
async fn main() {
    let hex_string = hex::encode(TEST_STRING);
    println!("{}", hex_string);

    let hex_string_decode = hex::decode(hex_string).unwrap();
    assert_eq!(TEST_STRING.to_owned().into_bytes(), hex_string_decode);
}

assert_eq!(TEST_STRING, hex_string_decode); ではないので、注意が必要。