【Rust】Rustのtry & catch

#![feature(catch_expr)]

use std::fs::File;
use std::io::{self, BufReader, Read};

fn main(){
    try {
        let f = File::open("foo.txt")?;
        let mut f = BufReader::new(f);
        let mut buf = String::new();
        f.read_to_string(&mut buf)?;
        println!("{}", buf);
        Ok(())
    }.unwrap_or_else(|err: io::Error| {
        eprintln!("An error occured: {}", err);
    })
}

try & catchではなく、matchで実装する

fn main(){
    let file_path = "foo.txt";
    match std::fs::remove_file(file_path) {
        Ok(()) => {},
        Err(e) => {
            eprintln!("Failed deleting file{}. Error caut:", file_path);
            // return Err(e);
        }
    }
}

$ ./main
Failed deleting filefoo.txt. Error caut:

true or falseの場合はifで大丈夫

fn main(){
    let private_key: SigningKey = SigningKey::from_bytes(&hex!(
        "DCDFF4B7CA287CC7BD30ECAEF0622265DB4E14054E12954225457C3A6B84F135"
    ).into()).unwrap();

    let public_key: &VerifyingKey = private_key.verifying_key();

    let message = b"hello, world";
    let signature: Signature = private_key.sign(message);

    let verified = public_key.verify(message, &signature).is_ok();

    println!("private key: {:X?}", hex(&private_key.to_bytes()));
    println!("public key: {:X?}", hex(&public_key.to_encoded_point(false).to_bytes()));
    println!("Signature: {:X?}", hex(&signature.to_bytes()));

    if verified {
            println!("文章は改竄されていません。");
        } else {
            println!("文章が改竄されています。");
        }

}

private key: “dcdff4b7ca287cc7bd30ecaef0622265db4e1454e12954225457c3a6b84f135”
public key: “4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123”
Signature: “f690afffd24623627bfa97996873a6a9d8ca8e9bb7ab6ad269c929453b42985573cdc4c05b8522224065757fef6c181c8418ffd3debdab4be22a73b2e5b6ce”
文章は改竄されていません。

【Rust】u8のバイト列を16進数hexに変換

fn hex(bytes: &[u8]) -> String {
    bytes.iter().fold("".to_owned(), |s, b| format!("{}{:x}", s, b))
}

fn main(){
    let s = hex(&[10, 32, 123]);
    println!("{:?}", s);
}

$ ./main
“a207b”

これを秘密鍵、公開鍵のコードに実装します。

use hex_literal::hex;
use k256::{ecdsa::{SigningKey, Signature, signature::Signer, signature::Verifier, VerifyingKey}};

fn hex(bytes: &[u8]) -> String {
    bytes.iter().fold("".to_owned(), |s, b| format!("{}{:x}", s, b))
}

fn main(){
    let private_key: SigningKey = SigningKey::from_bytes(&hex!(
        "DCDFF4B7CA287CC7BD30ECAEF0622265DB4E14054E12954225457C3A6B84F135"
    ).into()).unwrap();

    let public_key: &VerifyingKey = private_key.verifying_key();

    let message = b"hello, world";
    let signature: Signature = private_key.sign(message);

    let verified = public_key.verify(message, &signature).is_ok();

    println!("private key: {:X?}", hex(&private_key.to_bytes()));
    println!("public key: {:X?}", hex(&public_key.to_encoded_point(false).to_bytes()));
    println!("message: {:X?}", message);
    println!("Signature: {:X?}", hex(&signature.to_bytes()));
    println!("verified: {:X?}", verified);

}

private key: “dcdff4b7ca287cc7bd30ecaef0622265db4e1454e12954225457c3a6b84f135”
public key: “4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123”
message: [68, 65, 6C, 6C, 6F, 2C, 20, 77, 6F, 72, 6C, 64]
Signature: “f690afffd24623627bfa97996873a6a9d8ca8e9bb7ab6ad269c929453b42985573cdc4c05b8522224065757fef6c181c8418ffd3debdab4be22a73b2e5b6ce”
verified: true

うん、いい感じ

【Rust】RustでSECP256k1

$ cargo add hex-literal k256

[dependencies]
chrono = "0.4.23"
hex-literal = "0.4.1"
k256 = "0.13.4"
use hex_literal::hex;
use k256::{ecdsa::{SigningKey, Signature, signature::Signer, signature::Verifier, VerifyingKey}};

fn main(){
    let private_key: SigningKey = SigningKey::from_bytes(&hex!(
        "DCDFF4B7CA287CC7BD30ECAEF0622265DB4E14054E12954225457C3A6B84F135"
    ).into()).unwrap();

    let public_key: &VerifyingKey = private_key.verifying_key();

    let message = b"hello, world";
    let signature: Signature = private_key.sign(message);

    let verified = public_key.verify(message, &signature).is_ok();

    println!("private key: {:X?}", private_key.to_bytes());
    println!("public key: {:X?}", public_key.to_encoded_point(false).to_bytes());
    println!("message: {:X?}", message);
    println!("Signature: {:X?}", signature.to_bytes());
    println!("verified: {:X?}", verified);

}

private key: [DC, DF, F4, B7, CA, 28, 7C, C7, BD, 30, EC, AE, F0, 62, 22, 65, DB, 4E, 14, 5, 4E, 12, 95, 42, 25, 45, 7C, 3A, 6B, 84, F1, 35]
public key: [4, BA, C6, CB, 0, F, 4, AD, 63, 97, 7, 52, C3, D7, 3B, 88, C5, C8, 6E, 3D, 88, AC, 69, 51, 18, 49, 4A, 1, 73, 2E, 2A, BD, 16, C7, 6A, CA, D3, D6, 58, 6C, 37, C8, DB, 7E, 69, C2, F8, 12, F9, 92, 75, 19, 89, 36, 95, 7D, 72, C3, 8D, 71, 9, 81, 99, 11, 23]
message: [68, 65, 6C, 6C, 6F, 2C, 20, 77, 6F, 72, 6C, 64]
Signature: [F6, 90, AF, FF, D2, 46, 23, 62, 7B, FA, 97, 99, 68, 73, A6, A9, D8, CA, 8E, 9B, B7, AB, 6A, D2, 69, C9, 29, 45, 3B, 42, 98, 55, 73, CD, C4, C0, 5B, 85, 22, 22, 40, 65, 75, 7F, EF, 6C, 18, 1, C8, 41, 8F, FD, 3D, EB, DA, B, 4B, E2, 2A, 73, B2, E5, B6, CE]
verified: true

【Rust】rustでblockchain

### トランザクション

use std::collections::HashMap;

fn main(){
    let transaction = HashMap::from([
        ("Time", "2024-12-20 13:58"),
        ("sender", "A"),
        ("receiver", "B"),
        ("amount", "1")
    ]);
    for (k, v) in &transaction {
        println!("{} {}", k, v);
    }
}

Hashmapだとkey, valueが全て同じ型になってしまうので、構造体を使用する。

#[derive(Debug)]

struct Transaction {
    time: String,
    sender: String,
    receiver: String,
    amount: i32,
}

fn main(){
    let t1 = Transaction {time: "2024-12-20 13:58".to_string(), sender: "A".to_string(), receiver: "B".to_string(), amount: 10};

    println!("{:?}", t1);
}

$ ./main
Transaction { time: “2024-12-20 13:58”, sender: “A”, receiver: “B”, amount: 10 }

複数トランザクションの場合は配列を使用する

fn main(){
    let t1 = Transaction {time: "2024-12-20 13:58".to_string(), sender: "A".to_string(), receiver: "B".to_string(), amount: 10};
    let t2 = Transaction {time: "2024-12-21 13:58".to_string(), sender: "B".to_string(), receiver: "C".to_string(), amount: 5};

    let transactions = [t1, t2];
    println!("{:?}", transactions);
}

### Rustで日時を扱う

use chrono::{Utc, Local, DateTime, Date};

fn main(){
    let utc_datetime: DateTime<Utc> = Utc::now();
    let utc_date: Date<Utc> = Utc::today();

    println!("{}", utc_datetime);
    println!("{}", utc_date);
}

2024-12-20 05:46:43.775637762 UTC
2024-12-20UTC

crateを使うには、Cargo.tomlを利用する

[package]
name = "hoge"
version = "0.1.0"
edition = "2021"

[dependencies]
chrono = "0.4.23"

凄い基本的なことを書くだけでも時間がかかりますな。。

use chrono::{Utc, Local, DateTime, Date};
#[derive(Debug)]

struct Transaction {
    time: String,
    sender: String,
    receiver: String,
    amount: i32,
}

fn main(){
    let utc_datetime: DateTime<Utc> = Utc::now();
    let t1 = Transaction {time: utc_datetime.to_string(), sender: "A".to_string(), receiver: "B".to_string(), amount: 10};
    let t2 = Transaction {time: utc_datetime.to_string(), sender: "B".to_string(), receiver: "C".to_string(), amount: 5};

    let transactions = [t1, t2];
    println!("{:?}", transactions);
}

[Transaction { time: “2024-12-21 06:09:35.567867379 UTC”, sender: “A”, receiver: “B”, amount: 10 }, Transaction { time: “2024-12-21 06:09:35.567867379 UTC”, sender: “B”, receiver: “C”, amount: 5 }]

【Rust】静的変数(static)

staticは静的変数を定義する。値は変動しても良いが、変数の位置が固定で、複数スレッドから共通に参照することができる。

static mut COUNTER: u32 = 0;

fn main(){
    unsafe {
        println!("{}", COUNTER);
        COUNTER += 1;
        println!("{}", COUNTER);
    }
}

安全に読み書きするには、アトミック性を保証する参照・変更を用いる。

use std::sync::atomic::{self, AtomicU32, Ordering};
static COUNTER: AtomicU32 = AtomicU32::new(0);
fn count_up() {COUNTER.fetch_add(1, atomic::Ordering::SeqCst);}
fn get_count()-> u32 { return COUNTER.load(Ordering::SeqCst); }

fn main(){
    unsafe {
        println!("{}", get_count());
        count_up();
        println!("{}", get_count());
    }
}

### C++
グローバル変数

static int a = 10;
extern int b;

int main(void) {
}

静的メンバ変数

#include <iostream>

static int num = 0;

struct Sample {
    
    void CountUp() {
        num++;
        std::cout << "num: " << num << std::endl;
    }
    
};

int main(void) {
    Sample instance1;
    instance1.CountUp();

    Sample instance2;
    instance2.CountUp();
}

C++

#include <iostream>

static int num = 0;

struct Sample {
    
    void CountUp() {
        num++;
        std::cout << "num: " << num << std::endl;
    }
    
};

int main(void) {
    Sample instance1;
    instance1.CountUp();

    Sample instance2;
    instance2.CountUp();
}
static mut num: i32 = 0;

struct Sample {
}

trait Count {fn CountUp(n: i32);}
impl Count for Sample {
    fn CountUp(n: i32) {
        n = n + 1;
        println!("{}", n);
    }
}


fn main(){
    let s1 = Sample {};
    s1.CountUp(num);

    let s2 = Sample {};
    s2.CountUp(num);
}

どう書いて良いかイマイチわからんな。。。

【Rust】外部関数の呼び出し(extern)

extern "C" {
    fn abs(x: i32) -> i32;
}

fn main(){
    unsafe {
        println!("{}", abs(-123));
    }
}

sub.h

#ifndef SUB_H
#define SUB_H

extern int gNumber;

#endif

sub.c

int gNumber = 100;

void func(void){
    gNumber += 100;
}

main.c

#include <stdio.h>
#include "sub.h"

int main(void) {
    func();
    printf("gNumber: %d\n", gNumber);
}

$ g++ -o test test.cpp sub.cpp && ./test
test.cpp: In function ‘int main()’:
test.cpp:5:5: error: ‘func’ was not declared in this scope
5 | func();

うーん、これはエラーになっちゃうな…

【Rust】型エイリアス(type)

fn main(){

    let x = 123;
    println!("{}", type_of(x));
}

fn type_of<T>(_: T) -> &'static str {
    std::any::type_name::<T>()
}

c++だと、typeid

#include <iostream>
#include <typeinfo>

struct Base {};
struct Derived : public Base {};

struct PolyBase {virtual void member(){}};
struct PolyDerived : public PolyBase {};


int main() {
    int i;
    int* pi;
    std::cout << "int is: " << typeid(int).name() << std::endl;
    std::cout << "i is: " << typeid(i).name() << std::endl;
    std::cout << "pi is: " << typeid(pi).name() << std::endl;
    std::cout << "*pi is: " << typeid(*pi).name() << std::endl;
    std::cout << std::endl;

    Derived derived;
    Base *pbase = &derived;
    std::cout << "derived is: " << typeid(derived).name() << std::endl;
    std::cout << "*pbase is: " << typeid(*pbase).name() << std::endl;
    std::cout << std::boolalpha << "same type? " << (typeid(derived) == typeid(*pbase)) << std::endl;
    std::cout << std::endl;

    PolyDerived polyderived;
    PolyBase* ppolybase = &polyderived;
    std::cout << "polyderived is: " << typeid(polyderived).name() << std::endl;
    std::cout << "*ppolybase is: " << typeid(*ppolybase).name() << std::endl;
    std::cout << std::boolalpha << "same type? " << (typeid(polyderived) == typeid(*ppolybase)) << std::endl;
}
fn main(){
    let i = 10;
    let j = 3.14;
    println!("{}", type_of(i));
    println!("{}", type_of(j));
}

fn type_of<T>(_: T) -> &'static str {
    std::any::type_name::<T>()
}

derivedは派生。rustはclassがなくstructとimplなので、baseとderivedという概念があるか不明。。

【Rust】型エイリアス(type)

typeを用いて型エイリアスという別名をつけることができる。

fn main(){
    type Meter = u32;
    type Millimeter = u32;
    let m: Meter = 12;
    let mm: Millimeter = 12000;
    println!("{} {}", m, mm);
}

C++のエイリアスはtypedefやusing

#include <vector>
#include <iostream>

template <class T>
using Vec = std::vector<T>;

int main() {
    Vec<int> v;
    v.push_back(3);
    v.push_back(1);
    v.push_back(4);

    for (auto item : v) {
        std::cout << item << ", ";
    }
    std::cout << std::endl;

    return 0;
}

vector型にエイリアスを使用する

fn main(){

    type v = Vec<i32>;

    let a: v = (0..5).collect();

    for b in &a {
        println!("{}", b);
    }
}

【Rust】所有権・移動・参照

JavaやJavaScriptなどでは、ヒープ領域に確保したメモリは誰からも参照されなくなった後にガーベジコレクションによって解放される。Rustでは、ただ一つの変数がヒープ上のメモリの所有権を持ち、所有者がスコープから消えた時点でヒープ領域も解放される。

fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
}

関数に変数を渡すと所有権が移る

fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
    func2(name);
    println!("{}", name);
}

fn func2(name: String){
    println!("{}", name);
}

所有権を返してもらうこともできる

fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
    name = func2(name);
    println!("{}", name);
}

fn func2(name: String) -> String{
    println!("{}", name);
    name
}

&で参照を渡すことで、所有権を移さないまま関数を呼び出すこともできる

fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
    name = func2(&name);
    println!("{}", name);
}

fn func2(name: &String){
    println!("{}", name);
}

関数内で他の変数に渡しただけでも所有権の移転が発生する

fn func1() {
    let s1 = String::from("ABC");
    {
        let s2 = s1;
        println!("{}", s2);
    }
}

c++でお馴染みのswap

#include <cstdio>

void swap(int &a, int &b)
{
    int temp;;
    temp = a;
    a = b;
    b = temp;
}

void swap_pointer(int *a, int *b){
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5;
    int y = 8;

    swap(x, y);
    printf("%d, %d\n", x, y);

    swap_pointer(&x, &y);
    printf("%d, %d\n", x, y);

    return(0);
}

rustでswapを書こうとすると上手くいかない

fn func1() {
    let s1 = String::from("ABC");
    {
        let s2 = s1;
        println!("{}", s2);
    }
}

fn func2(name: &String){
    println!("{}", name);
}

fn main(){
    let mut x: i32 = 5;
    let mut y: i32 = 8;
    swap(&x, &y);
    println!("x:{} y:{}", x, y);
}

$ ./main
x:5 y:8

【Rust】参照型(&, *)

fn main(){
    let a = 123;
    let p = &a;
    println!("{}", *p);

    let b = 456;
    let ref q = &b;
    println!("{}", *q);

    let c = 789;
    let ref r = &c;
    println!("{}", *r);
}
#include <cstdio>

void swap(int &a, int &b)
{
    int temp;;
    temp = a;
    a = b;
    b = temp;
}

void swap_pointer(int *a, int *b){
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5;
    int y = 8;

    swap(x, y);
    printf("%d, %d\n", x, y);

    swap_pointer(&x, &y);
    printf("%d, %d\n", x, y);

    return(0);
}

これをRustで書こうとするが、、、

fn swap<'a>(mut a: &'a i32,mut b: &'a i32) {
    let mut _temp:&i32;

    _temp = a;
    a = b;
    b = _temp;
}

fn main(){
    let mut x: i32 = 5;
    let mut y: i32 = 8;
    swap(&x, &y);
    println!("x:{} y:{}", x, y);
}

$ ./main
x:5 y:8

swapされんな… 何が間違っているかよくわからん…