lasciva blog

開発して得た知見やwebビジネスのストック

「実践 Rustプログラミング入門」を読んだ

全体の感想

他の言語を普段使っていてRustに触れたことがない人にとっては、良い本だと思った。
3部からなり、第1部では基礎的な文法から、Rust特有の考え方(GCの所有権、メモリ安全性、スレッド安全性など)の説明があった。第2部では、実践的なアプリケーションを実装して、コマンドラインツールやWebアプリケーション、GUI、組み込みなど幅広く扱われていた。第3部では、応用的なtipsが紹介されていて、他の言語との連携や、コミュニティ、リリースサイクルなどについて言及されていた。

Rust言語自体は、パフォーマンスがよく、型推論も強くサポートされ、モダンな言語にある機能はほとんど網羅されており、コミュニティも活発で幅広いアプリケーションやツールも作れそうで、いろんな企業が導入し始めてるのも納得できた。特にスレッド安全性などについては、言語の通りに実装すれば未然にバグも防げそうに感じたので、強力だなと思った。
一部パフォーマンスが求められる部分だけRustで書くことも結構簡単にできそうなので、部分的に導入するのも良さそうだと思った。

目次

概要

Part 1 入門

Chapter1 プログラミング言語 Rust

1-2 とにかく実行速度が速い

  • Rust は機械語に直接コンパイルされる
  • ガベージコレクションをもたない
    • 「所有権」「借用」「ライフタイム」という新しい仕組みで、言語側で管理する
  • 「ゼロコスト抽象化」を追求している
    • 抽象化するときにオーバーヘッドとかが生じないようになっている。

1-4 OS から Web アプリケーションまで幅広く実装できる

Chapter3 Rustの基本

3-1 基本的な文法

  • NaNは ==を満たさないので、f32では PartialEqPartialOrdを使う

3-2 Rustを支える言語機能

所有権と借用
  • メモリ管理のために、所有できるのは1つのオブジェクトだけ
  • 参照は複数から行えるので、参照渡しをする
    • 可変の場合は、一度に一つだけ
    • 不変の場合は、制限なし
  • デストラクタとして Dropトレイトが用意されている
スレッド安全性

マルチスレッドの例

use std::thread;

fn main() {
    let mut handlers = Vec::new();
    for x in 0..10 {
        // moveキーワードで所有権をスレッドに移す
        handlers.push(thread::spawn(move || {
            println!("Hello, world!: {}", x);
        }));
    }

    for handle in handles {
        // スレッドの処理が終了するのを待つ
        let _ = handle.join();
    }
}

共有メモリ

use std::rc::{Arc, Mutex};
use std::thread;

fn main() {
  let mut handlers = Vec::new();
  let data = Arc::new(Mutex::new(vec![1; 10]));
  for x in 0..10 {
    // リファレンスカウンターを増やす
    let data_ref = data.clone();
    handlers.push(thread::spawn(move || {
      // 可変参照を得る
      let mut data = data_ref.lock().unwrap();
      data_ref[x] += 1;
    }));
  }

  for handle in handles {
    // スレッドの処理が終了するのを待つ
    let _ = handle.join();
  }

  dbg!(data);
}

メッセージパッシング

use std::sync::mpsc;
use std::thread;

fn main() {
  let mut handles = Vec::new();
  let mut data = vec![1; 10];
  let mut snd_channels = Vec::new();
  let mut rcv_channels = Vec::new();

  for _ in 0..10 {
    let (snd_tx, snd_rx) = mpsc::channel();
    let (rcv_tx, rcv_rx) = mpsc::channel();
    snd_channels.push(snd_tx);
    rcv_channels.push(rcv_tx);

    handlers.push(thread::spawn(move || {
      let mut data = snd_rx.recv().unwrap();
      data += 1;
      let _ = rcv_tx.send(data);
    }));
  }

  for x in 0..10 {
    let _ = snd_channels[x].send(data[x]);
  }

  for x in 0..10 {
    data[x] = rcv_channels[x].recv().unwrap();
  }

  for handle in handlers {
    let _ = handle.join();
  }
  dbg!(data)
}

Part 2 実践

ソースコードはこちら。

github.com

Chapter4 プログラムを作成する

逆ポーランド記法コマンドラインツールを作成した。

Chapter5 Webアプリケーションの開発

The Rust Programming Language

Chapter6 WebAssembly

6-4 サンプルプログラム:ナンバープレースを解く

数独を解く。

JSと比較したベンチマークの結果では、JITコンパイラの最適化の影響のためか、必ずしもRustの方が速いとは限らないみたいだった。

Untitled

Chapter7 GUIアプリケーション

IcedというGUIフレームワークのようなライブラリを使って、タイマーのアプリケーションを作成した。

7-1 RustにおけるGUIの現状

GUIクレートの紹介

Chapter8 組み込みシステム

エミュレータを使って、LEDをチカチカさせるものの実装の仕方が紹介されていた。

Chapter9 開発ツール

9-2 フォーマッタ・リンター

9-3 コードカバレッジ

9-4 ベンチマーク・プロファイラ

Chapter10 プロダクトをリリースする

10-2 ビルドの再現性

  • Cargo.lock: 依存クレートのバージョン
  • rust-toolchain: コンパイラのバージョン

10-3 バイナリサイズの最適化

最適化のオプション
[prifile.release]
// Link Time Optimization
lto = true

// 0: 最適化なし
// 1: 基本的な最適化
// 2: 追加の最適化
// 3: すべての最適化(リリースビルドでのデフォルト)
// "s": バイナリサイズの最適化
// "z": バイナリサイズの最適化(ループのベクトル化を行わない)
opt-level = "z"

// コンパイル時の並列度を下げることで、タスクをまたいだ最適化を行える
codegen-units = 1

// panic時、スタックを巻き戻してバックトレースを生成する必要がないとき
panic = "abort"

// シンボル情報の削除
$ strip ./target/release/hello

10-6 ファジング

cargo-fuzzを使える。

Part 3 Tips

Chapter11 いろいろなRustの発展的Tips

11-2 FFIによる他言語との連携

FFI(Foreign Function Interface)によって、他言語と簡単に連携できる。

11-4 unsafe

Rustはメモリ安全性を保証しているが、実装者の責任によってその安全性を無視して実装することができる。

  • 極力使わないこと
  • 使う場合は、局所的に使うこと
UB (未定義動作)

アプリケーションがライブラリやコンパイラの規約を守らなかったために、どのような動作結果も保証されない状態。

参考資料

11-5 Rust のエディション

Rustでは通常のリリースは6週間ごとに行われている。

大きな変更に関しては、約3年毎にエディションという単位でリリースされる。エディションは互換性があり、クレートごとに指定できる。

11-6 Rust製のOSS

rust-unofficial/awesome-rust

特にすぐ使える有名なもの

11-7 Rust のコミュニティ

最新情報を得るために

次のアクション

もう少し、バックエンドで本番運用できそうか、試してみる。