【Rust】rustでblockchain

### トランザクション

1
2
3
4
5
6
7
8
9
10
11
12
13
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が全て同じ型になってしまうので、構造体を使用する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#[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 }

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

1
2
3
4
5
6
7
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で日時を扱う

1
2
3
4
5
6
7
8
9
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を利用する

1
2
3
4
5
6
7
[package]
name = "hoge"
version = "0.1.0"
edition = "2021"
 
[dependencies]
chrono = "0.4.23"

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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は静的変数を定義する。値は変動しても良いが、変数の位置が固定で、複数スレッドから共通に参照することができる。

1
2
3
4
5
6
7
8
9
static mut COUNTER: u32 = 0;
 
fn main(){
    unsafe {
        println!("{}", COUNTER);
        COUNTER += 1;
        println!("{}", COUNTER);
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
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++
グローバル変数

1
2
3
4
5
static int a = 10;
extern int b;
 
int main(void) {
}

静的メンバ変数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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)

1
2
3
4
5
6
7
8
9
extern "C" {
    fn abs(x: i32) -> i32;
}
 
fn main(){
    unsafe {
        println!("{}", abs(-123));
    }
}

sub.h

1
2
3
4
5
6
#ifndef SUB_H
#define SUB_H
 
extern int gNumber;
 
#endif

sub.c

1
2
3
4
5
int gNumber = 100;
 
void func(void){
    gNumber += 100;
}

main.c

1
2
3
4
5
6
7
#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)

1
2
3
4
5
6
7
8
9
fn main(){
 
    let x = 123;
    println!("{}", type_of(x));
}
 
fn type_of<T>(_: T) -> &'static str {
    std::any::type_name::<T>()
}

c++だと、typeid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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;
}
1
2
3
4
5
6
7
8
9
10
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を用いて型エイリアスという別名をつけることができる。

1
2
3
4
5
6
7
fn main(){
    type Meter = u32;
    type Millimeter = u32;
    let m: Meter = 12;
    let mm: Millimeter = 12000;
    println!("{} {}", m, mm);
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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型にエイリアスを使用する

1
2
3
4
5
6
7
8
9
10
fn main(){
 
    type v = Vec<i32>;
 
    let a: v = (0..5).collect();
 
    for b in &a {
        println!("{}", b);
    }
}

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

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

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

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

1
2
3
4
5
6
7
8
9
10
fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
    func2(name);
    println!("{}", name);
}
 
fn func2(name: String){
    println!("{}", name);
}

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

1
2
3
4
5
6
7
8
9
10
11
fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
    name = func2(name);
    println!("{}", name);
}
 
fn func2(name: String) -> String{
    println!("{}", name);
    name
}

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

1
2
3
4
5
6
7
8
9
10
fn func1() {
    let name = String::from("ABC");
    println!("{}", name);
    name = func2(&name);
    println!("{}", name);
}
 
fn func2(name: &String){
    println!("{}", name);
}

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

1
2
3
4
5
6
7
fn func1() {
    let s1 = String::from("ABC");
    {
        let s2 = s1;
        println!("{}", s2);
    }
}

c++でお馴染みのswap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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を書こうとすると上手くいかない

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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】参照型(&, *)

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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で書こうとするが、、、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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されんな… 何が間違っているかよくわからん…

【Rust】モジュール(mood, pub, use, as)

modはモジュールを使用することを宣言する。pubはモジュール外からもその名前にアクセスするために必要。

foo.rs

1
2
3
pub fn foo_func() {
    println!("Foo!");
}

main.rs

1
2
3
4
5
mod foo;
 
fn main() {
    foo::foo_func();
}

先ほどの例を記述すると
foo.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pub fn add(a: f32, b: f32) -> f32 {
    a + b
}
 
pub fn subtract(a: f32, b: f32) -> f32 {
    a - b
}
 
pub fn multiply(a: f32, b: f32) -> f32 {
    a * b
}
 
pub fn divide(a: f32, b: f32) -> f32 {
    a / b
}

main.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mod foo;
 
fn main() {
    let a: f32 = 7.4;
    let b: f32 = 99.0;
 
    let x = foo::add(a, b);
    println!("a + b = {}", x);
    let y = foo::subtract(a, b);
    println!("a - b = {}", y);
    let z = foo::multiply(a, b);
    println!("a * b = {}", z);
    let d = foo::divide(a, b);
    println!("a / d = {}", d);
}

$ cargo run
Compiling hoge v0.1.0 (/home/vagrant/dev/rust/hoge)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.97s
Running `target/debug/hoge`
a + b = 106.4
a – b = -91.6
a * b = 732.60004
a / d = 0.07474747

ヘッダーファイルが無い分、C++よりスッキリしてますね。。

【Rust】Cargoの使い方とcrate(クレート)

### cargoがインストールされていることを確認
$ cargo –version
cargo 1.83.0 (5ffbef321 2024-10-29)

## プロジェクトの作成
$ cargo new hoge

main.rs

1
2
3
4
5
6
7
8
use rand::Rng;
 
fn main() {
    let mut rng = rand::thread_rng();
    for _i in 1..10 {
        println!("{}", rng.gen_range(1, 101));
    }
}

Cargo.tom

1
2
3
4
5
6
7
[package]
name = "hoge"
version = "0.1.0"
edition = "2021"
 
[dependencies]
rand = "0.7"

$ cargo run
26
4
61
71
29
17
33
37
59

### C++でライブラリを作る
MathLibrary.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
 
namespace MathLibrary
{
    class Arithmetic
    {
    public:
        static double Add(double a, double b);
 
        static double Subtract(double a, double b);
 
        static double Multiply(double a, double b);
 
        static double Divide(double a, double b);
    };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "MathLibrary.h"
 
namespace MathLibrary
{
    double Arithmetic::Add(double a, double b)
    {
        return a + b;
    }
 
    double Arithmetic::Subtract(double a, double b)
    {
        return a - b;
    }
 
    double Arithmetic::Multiply(double a, double b)
    {
        return a * b;
    }
 
    double Arithmetic::Divide(double a, double b)
    {
        return a / b;
    }
 
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include "MathLibrary.h"
 
int main() {
    double a = 7.4;
    int b = 99;
 
    std::cout << "a + b = " <<
        MathLibrary::Arithmetic::Add(a, b) << std::endl;
    std::cout << "a - b = " <<
        MathLibrary::Arithmetic::Subtract(a, b) << std::endl;
    std::cout << "a * b = " <<
        MathLibrary::Arithmetic::Multiply(a, b) << std::endl;
    std::cout << "a / b = " <<
        MathLibrary::Arithmetic::Add(a, b) << std::endl;
}

$ g++ -o test MathLibrary.cpp test.cpp && ./test
a + b = 106.4
a – b = -91.6
a * b = 732.6
a / b = 106.4

crateというより、複数ファイルの使用か…

【Rust】非同期関数(async, await)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
use futures::executor::block_on;
 
struct Song {
    lyric: String,
}
 
async fn learn_and_sing() {
    let song = learn_song().await;
    sing_song(song).await;
}
 
async fn learn_song() -> Song {
    let song = Song { lyric: String::from("La la la...") }
    println!("Learned song");
    return song;
}
 
async fn sing_song(song: Song) {{
    println!("{}", song.lyric);
}}
 
async fn dance() {
    println!("Dance");
}
 
async fn async_main(){
    let f1 = learn_and_sing();
    let f2 = dance();
    futures::join!(f1, f2);
}
 
fn main(){
    block_on(async_main());
}

to use `async fn`, switch to Rust 2018 or later
2015 Rustだと使えない模様

c++の非同期処理

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <future>
 
int main() {
    std::promise<int> pr;
    std::future<int> ft = pr.get_future();
    pr.set_value(100);
    int i = ft.get();
    std::cout << i << std::endl;
}