【Rust】文字列

Rustの基本的な文字列型は&strを使用する。

fn main(){
    let mut name: &str = "Yamada";

    println!("{}", name);

    name = "Tanaka";

    println!("{}", name);
}

ライブラリとして提供されている文字列にStringがある。

fn main(){
    let mut name = String::from("Yamada");

    name = "Tanaka".to_string();
    name.push_str(" Taro");
    println!("{}", name);
}

C++のchar型は1文字のみ

#include <stdio.h>

int main(void)
{
    char a = 'D';
    char b = 'N';
    char c = 'A';

    printf("%c%c%c\n", a, b, c);
    return 0;

}

複数文字は配列

#include <stdio.h>

int main(void)
{
    char str1[] = "DNA";

    printf("%s\n", str1);
    printf("%lu\n", sizeof(str1));

    return 0;

}

char型のポインタ

int main(void)
{
    const char* char_ptr = "DNA";

    printf("%s\n", char_ptr);

    return 0;

}

string型

#include <stdio.h>
#include <string>
#include <iostream>

int main(void)
{
    std::string str1 = "DNA";
    std::string str2 = "RNA";
    std::string str3 = str1 + str2;

    std::cout << str3 << std::endl;

    return 0;

}
fn main(){
    let s1 = String::from("ABC");
    let s2 = String::from("ABC");
    let s3 = String::from("XY");

    if(s1 == s2){
        println!("ABC == ABC");
    }
    if(s1 < s3) {
        println!("ABC < XY");
    }
}

String::fromが便利すぎる。。

【Rust】ハッシュマップ(Hashmap)

ハッシュマップは文字列を添字に使用することができる。他の言語では連想配列と呼ばれる。

use std::collections::HashMap;

fn main(){
    let mut map = HashMap::new();
    map.insert("x", 10);
    map.insert("y", 20);
    map.insert("z", 30);

    println!("{} {} {}", map["x"], map["y"], map["z"]);

    for (k, v) in &map {
        println!("{} {}", k, v);
    }
}

C++

#include <iostream>
#include <map>
#include <string>

using namespace std;

int main()
{
    map<int, string> Players;

    Players.insert(std::pair<int, string>(2, "Lin Dan"));
    Players.insert(std::pair<int, string>(1, "Chen Long"));

    cout << "Number of Players " << Players.size() << endl;
    for(map<int, string>::iterator it = Players.begin(); it != Players.end();
        ++it){
            cout << (*it).first << ": " << (*it).second << endl;
        }

}
use std::collections::HashMap;

fn main(){
    let mut Players = HashMap::new();
    Players.insert(2, "Lin Dan");
    Players.insert(1, "Chen Long");

    println!("{}", Players.len());

    for (k, v) in &Players {
        println!("{}: {}", k, v);
    }
}

$ ./main
2
1: Chen Long
2: Lin Dan

【Rust】ベクタ(vector)

ベクタは型の異なる要素を含めることはできない。要素数は可変。インデックスに変数を使用することができる。

fn main(){
    let mut vect = vec![10, 20, 30];
    vect.push(40);
    println!("{} {} {} {}", vect[0], vect[1], vect[2], vect[3]);

    for v in &vect {
        println!("{}", v);
    }
}

C++

#include <vector>
#include <stdio.h>

int main(void)
{
    std::vector<int> vec{1,2,3};

    for(int i = 0; i < vec.size(); i++)
        printf("%d", vec[i]);
    printf("\n");

    return 0;
}
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> words = {"apple", "bird", "cat"};

    std::cout << words.size() << '\n';

    for(const auto& word : words)
    {
        std::cout << word << ' ';
    }

    std::cout << '\n';
}

rustの場合はsizeではなくlenで書く。

fn main(){
    let words = vec!["apple", "bird", "cat"];

    println!("{}", words.len());

    for w in &words {
        println!("{}", w);
    }
}

【Rust】配列

配列はTという単一の型のオブジェクトの集合。それらのオブジェクトはメモリ上の連続した領域に保存される。

fn main(){
    let arr = [10, 20, 30];
    println!("{}, {}, {}", arr[0], arr[1], arr[2]);

    for v in &arr {
        println!{"{}", v};
    }
}

C++の配列

#include <iostream>

void PrintArray1(const int x[5]){
    static_assert(sizeof(x) == sizeof(int*), "");
    for (int i = 0; i < 5; ++i){
        std::cout << x[i] << std::endl;
    }
}

void PrintArray2(const int* x) {
    for (int i = 0; i < 5; ++i){
        std::cout << x[i] << std::endl;
    }
}

int main()
{
    int x[5] = {0, 1, 2, 3, 4};

    PrintArray1(x);
    PrintArray2(x);

    return 0;
}

↓ Rustで書くことこうなる

fn PrintArray1(ary: [i32; 5]) {
    for i in ary {
        println!{"{}", i};
    }
}

fn main(){
    let x: [i32; 5]= [0, 1, 2, 3, 4];

    PrintArray1(x);
}

関数の引数は明確に定義しないといけない。

【Rust】タプル

タプルは異なる型の値の集合。括弧を用いて生成する。

fn main(){
    let tup = (10, "20", 30);
    println!("{}, {}, {}", tup.0, tup.1, tup.2);
}

C++でタプルを使用する場合は、型を指定しなければいけないが、Rustの場合は型指定がない。つまり自動で型推論をやってくれている?

#include <iostream>
#include <string>
#include <tuple>
#include <vector>

int main()
{
    std::tuple<int, double, std::string> t1{100, 1.1, "aaa"};
    std::tuple<std::string, int, int> t2{"bbb", 200, 300};
    std::vector<std::tuple<std::string, int, int>> v =
    {
        {"ccc", 400, 500},
        {"ddd", 600, 700}
    };
}

Rustではインデックスを用いて値にアクセスできるが、以下のような書き方をするとエラーとなる。

fn main(){
    let tup = (1, 1.2, "tupple");
    for n in 0..2 {
        println!("{}", tup.n);
    }
}

$ rustc main.rs
error[E0609]: no field `n` on type `({integer}, {float}, &str)`
–> main.rs:4:28
|
4 | println!(“{}”, tup.n);
| ^ unknown field

error: aborting due to 1 previous error

For more information about this error, try `rustc –explain E0609`.

また、型推論できない場合は、型を明示する必要がある。

【Rust】列挙型

### 定数値として扱う

enum Color {
    Red = 0x0000FF,
    Green = 0x00FF00,
    Blue = 0xFF0000,
}
fn main(){
    let color = Color::Red;
    println!("{}", color as usize);
}

### 特定の値を指定しない時

enum Color {
    Red,
    Green,
    Blue,
}
fn main(){
    let color = Color::Red as usize;
    println!("{}", color);
}

### 値を持つ列挙型

enum Color {
    RGB(u8, u8, u8),
    RGBA(u8, u8, u8, u8),
}
fn main(){
    let c = Color::RGB(0, 0, 255);
    let code = match c {
        Color::RGB(r, g, b) => b as u32 + ((g as u32) << 8) + ((r as u32) << 16),
        Color::RGBA(r, g, b, _) => b as u32 + ((g as u32) << 8) +  ((r as u32) << 16),   
    };
    println!("{}", code);
}

### 値を持つenumを比較

#[derive(Debug,PartialEq)]
enum Animal {
    Dog(String),
    Cat(String),
    Monkey(String),
}

fn main(){
    let taro1 = Animal::Dog(String::from("Taro"));
    let taro2 = Animal::Dog(String::from("Taro"));
    assert_eq!(taro1, taro2);

    let taro3 = Animal::Cat(String::from("Taro"));
    let taro4 = Animal::Dog(String::from("Taro"));
    assert_eq!(taro3, taro4);

    let taro5 = Animal::Monkey(String::from("Taro"));
    let taro6 = Animal::Monkey(String::from("Taro"));
    // println!(taro5 as usize, taro6 as usize);
}

値を持つ、持たないで扱いが異なるのね。。
列挙型と構造体は何となく似ているが、列挙型は名前を列挙していくだけなので、型指定はしない。

【Rust】構造体と共用体

### 構造体

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 100, y: 200};
    println!("{} {}", p.x, p.y);
}

### 共用体
共用体は同じメモリを使用する

union MyUnion {
    f1: u32,
    f2: u32,
}

fn main() {
    let u = MyUnion {f1: 123};
    unsafe {
        println!("{}", u.f1);
        println!("{}", u.f2);
    }
}

$ ./main
123
123

【Rust】Ubuntu24.04にRustをインストールする

### rustが入っていない状態
$ cargo –version
bash: cargo: command not found

### インストール
$ cd $home
$ sudo apt-get update
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang cmake make libprotobuf-dev protobuf-compiler
$ curl –proto ‘=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env

### 最新バージョンの確認
$ rustup component add rustfmt
$ rustup update

### インストール確認
$ cargo –version
cargo 1.83.0 (5ffbef321 2024-10-29)
$ rustc –version
rustc 1.83.0 (90b35a623 2024-11-26)

【Python】非同期処理を理解する

### 非同期処理とは?
あるタスクが終了するのを待っている間、別のタスクを実行すること

$ pip3 install aiohttp

import datetime
import aiohttp
import asyncio

start = datetime.datetime.now()

def log(message):
    print(f'{(datetime.datetime.now() - start).seconds}秒経過', message)

async def fetch(session, url):
    """ 非同期にURLからデータを取得 """
    print(f"Fetching {url}")
    async with session.get(url) as response:
        return await response.text()

async def main():
    log("タスク開始")
    urls = [
        "http://google.com",
        "http://qiita.com",
        "https://www.python.org/",
        "https://www.mozilla.org/en-US/",
        "https://html.spec.whatwg.org/multipage/",
        "https://www.w3.org/TR/css/",
        "https://ecma-international.org/",
        "https://www.typescriptlang.org/",
        "https://www.oracle.com/jp/java/technologies/",
        "https://www.ruby-lang.org/ja/",
        "https://www.postgresql.org/",
        "https://www.mysql.com/jp/",
        "https://docs.djangoproject.com/ja/5.0/",
        "https://spring.pleiades.io/projects/spring-boot",
        "https://rubyonrails.org/"
        "https://firebase.google.com/?hl=ja",
        "https://go.dev/",
        "https://nodejs.org/en"
    ]

    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]

        print("Starting tasks...")

        print("Tasks are running in the background...")

        results = await asyncio.gather(*tasks)

        for result in results:
            print(result[:100])

    log("task finished")

if __name__ == "__main__":
    asyncio.run(main())

【Python】threadingによる並列処理(マルチスレッド)

threadingというライブラリを使用する
今いるスレッドを確認

import threading
import warnings
warnings.simplefilter('ignore')

print(threading.currentThread().getName())

$ python3 main.py
MainThread

### threading.Threadでmainとは別にスレッドを作成する

import threading
import time
import warnings
warnings.simplefilter('ignore')

def boil_udon():
    print(" ■ thread :", threading.currentThread().getName())

    print(' うどんを茹でます。')
    time.sleep(3)
    print(' うどんが茹で上がりました。')

if __name__ == "__main__":
    print(" ■ thread :", threading.currentThread().getName())

    print('うどんを作ります。')

    # スレッドを作成
    thread1 = threading.Thread(target=boil_udon)
    thread1.start()
    thread1.join()

    print('うどんの盛り付けをします。')
    print('うどんができました。')

$ python3 main.py
■ thread : MainThread
うどんを作ります。
■ thread : Thread-1 (boil_udon)
うどんを茹でます。
うどんが茹で上がりました。
うどんの盛り付けをします。
うどんができました。

### スレッドを更に追加する

import threading
import time
import warnings
warnings.simplefilter('ignore')

def boil_udon():
    print(" ■ thread :", threading.currentThread().getName())

    print(' うどんを茹でます。')
    time.sleep(3)
    print(' うどんが茹で上がりました。')

def make_tuyu():
    print(" ■ thread :", threading.currentThread().getName())

    print(' うどんの汁を作ります。')
    time.sleep(2)
    print(' うどんの汁ができました。')


if __name__ == "__main__":
    print(" ■ thread :", threading.currentThread().getName())

    print('うどんを作ります。')

    # スレッドを作成
    thread1 = threading.Thread(target=boil_udon)
    thread2 = threading.Thread(target=make_tuyu)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print('うどんの盛り付けをします。')
    print('うどんができました。')

$ python3 main.py
■ thread : MainThread
うどんを作ります。
■ thread : Thread-1 (boil_udon)
うどんを茹でます。
■ thread : Thread-2 (make_tuyu)
うどんの汁を作ります。
うどんの汁ができました。
うどんが茹で上がりました。
うどんの盛り付けをします。
うどんができました。

threadが作られると、同時に処理されていることがわかる
ThreadPoolExecutorの場合は、単純に1つの処理を複数のスレッドで実行するが、threadingの場合は、プログラム内容を指定してスレッドを作成することができる