kdnakt blog

hello there.

Rust dojo第75回を開催した

第75回です。前回はこちら。

kdnakt.hatenablog.com

[第75回の様子]

2023/04/19に第75回を開催した。

内容としてはRust By Example 日本語版20. 標準ライブラリのその他の「20.7. 引数処理」、「20.7.1. 引数のパース」、「20.8. 他言語関数インターフェイス」に取り組んだ。
参加者は自分を入れて6人。今回は詳しい人がドライバやってくれたので、色々と解説聴きながら進められてよかった!

[学んだこと]

  • 20.7. 引数処理
  • Rustでプログラムの引数を取得する場合std::env::args()関数を利用できる
  • 戻り値はArgsという構造体で、イテレータになっているので、collect()してベクタに変換できる
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    println!("My path is {}.", args[0]);

    println!("I got {:?} arguments: {:?}.", args.len() - 1, &args[1..]);
}

// 実行結果はこうなる
$ ./args 1 2 3
My path is ./args.
I got 3 arguments: ["1", "2", "3"].
  • Javaとかだとpublic static void main(String[] args)みたいにメイン関数の引数にコマンドライン引数が渡ってくるが、rustでは上でみたように標準ライブラリから取得する
    • CとかもRustと似たような感じになっていて、それらはOSのない環境での実行のためにそうなっているらしい
    • ちょっと面白い
  • とはいえ通常はclapのようなクレートを使って引数を処理するのが一般的らしい
  • clapの使い方はこんな感じ
use clap::Parser;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Name of the person to greet
    #[arg(short, long)]
    name: String,

    /// Number of times to greet
    #[arg(short, long, default_value_t = 1)]
    count: u8,
}

fn main() {
    let args = Args::parse();

    for _ in 0..args.count {
        println!("Hello {}!", args.name)
    }
}
  • 20.7.1. 引数のパース
  • clapなどのクレートを使わない場合、自分でパース処理を実装することになる
    • サンプルコードは長いので省略...元サイトを参照してほしい
  • 気になったのは、引数をStringで受け取ってi32にパースして処理する部分
  • i32の最大値を入力して1を足した場合どうなるのだろう?と思ってやってみたら案の定パニックした
fn main() {
    // i32の最大値
    let num = "2147483647";
    let number: i32 = match num.parse() {
        Ok(n) => n,
        Err(_) => return,
    };
    println!("{}", number + 1);
}

// パニックした時のエラー
   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.63s
     Running `target/debug/playground`
thread 'main' panicked at 'attempt to add with overflow', src/main.rs:8:20
  • ただ、これは必ずしもパニックするわけではなく、コンパイル時にリリースビルドにしているとオーバーフローするらしい
  • 調べてみると、リリースビルドでもパニックさせる方法もあった

qiita.com

  • 他の言語でいうと、オーバーフロー時の挙動を演算子ベースで選択できるものもあるらしい
    • Zigでは3種類も演算子が用意されている:エラーとなる、2の補数となる、最大値となるの3種

ziglang.org

zenn.dev

// libmライブラリをリンクする。
#[link(name = "m")]
extern {
    fn csqrtf(z: Complex) -> Complex;
    fn ccosf(z: Complex) -> Complex;
}

// 単精度浮動小数複素数型の最小限の実装
#[repr(C)]
#[derive(Clone, Copy)]
struct Complex {
    re: f32,
    im: f32,
}

// 外部ライブラリは常にunsafeなので、型安全にするためのラッパ
fn cos(z: Complex) -> Complex {
    unsafe { ccosf(z) }
}
  • C++で書かれたライブラリの場合、そちらにextern Cを足してRustから参照することができる
  • あるいは、以下のクレートを用いて直接RustからC++を利用することもできる

cxx.rs

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。
改めて、レイヤが低い言語というのが少しだけわかった気がする。

今週はプルリクエストなし。