Rustで遊ぼう

この記事はEPOCH-NET Advent Calendarの12日目です。

自己紹介

初めまして。11月から株式会社EPOCH-NETでアルバイトをしているEsurioと申します。
今回のアドカレの主催です。
趣味でSNSのサーバー管理などをしたりSNSを改造して遊んだりRustでCLIツールを作ったりしています。

Rustとは

「効率的で信頼できるソフトウェアを誰もがつくれる言語」です。
関数型、手続型、オブジェクト指向などの実装をサポートしているマルチパラダイムな言語であり、CやC++に代わるシステムプログラミング言語を目指しています。

メモリ管理を所有権という機能で管理しており、これによってメモリ安全性を担保しています。所有権を利用するメリットとして、CやC++のように明示的にメモリを確保したり、JavaのようにGCによるメモリ管理をしなくて済む、というものがあります。この機能について詳しく書くと記事1本分になるので、詳しくはこちらをご覧ください。

身の回りのRust

Rustで書かれたものは身近に存在します。

例えば、Firefoxのレンダリングエンジン、一部のWindowsのコンポーネント、Androidのカーネル、Linux 6.1以降のNVMeドライバなどです。

DiscordやDropbox、CloudflareもRustを採用しています。

TypeScriptを使う人にとっても縁があります。npmjs.comもpublish時のボトルネックを改善するためにRustを使用しましたし、ランタイムの一つであるDenoはRustによって書かれています。

なぜRustか

私がRustを好んで書く理由としては、パフォーマンスと信頼性の高さ、優秀なエコシステムによる生産性の高さ、できることの多さがあります。

パフォーマンス

Rustは実行パフォーマンスが非常に高いです。C++と同程度かそれ以上のパフォーマンスを誇ります。
Rustは直接機械語にコンパイルされるため、CやC++と同程度の実行速度を誇ります。

信頼性

先ほども述べた通り、所有権という仕組みによってメモリ安全性が担保されています。また、型エラーなどが存在する場合コンパイラがエラーを出力するため、バグが比較的少なく済みます。
静的型付けであることも大事です。Rustの強力な型システムによって、Javascriptのような1 + "1" = 11という不具合が防げます。

優秀なエコシステム

Rustのエコシステムは優秀です。Node.jsにnpmがあるように、RustにはCargoというツールがあります。Node.jsはESLintやPrettierを自分でセットアップする必要がありますが、CargoではデフォルトでLinterとFormatterが同梱されています。さらに、Cargoはサブコマンドを自分自身で実装することで、簡単に拡張可能です。

rust-analyzerという拡張機能も優秀です。rust-analyzerはRustの入力補完や型チェック、文法ミスのチェックなどを行うための言語サーバープロトコルです。この拡張機能のおかげで毎度ビルドせずにコンパイルエラーを確認することができます。Vim/NeovimでもEmacsでも使えます。

できることの多さ

Rustはとにかくできることが多いです。

  • CLIツール
  • WebAssemblyを利用したフロントエンド開発
  • Webサーバーのバックエンド開発
  • 組み込み
  • OSカーネル開発
  • ゲーム開発
  • ネイティブアプリケーション開発

ここにあげたこと以外にも様々なことができます。

Rustで遊んでみよう

Rustで実際に遊んでみましょう。

Unix系OSであれば次のコマンドを実行してください。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Windowsの場合、この手順に従ってください。

これでRustの環境構築は終了です。

Hello worldをやってみましょう。
拡張子を*.rsで作成します。

fn main() {
  println!("Hello, world!");
}

コンパイルしてみましょう。gccとrustcが入っている状態で次を実行します。

rustc main.rs
./main

ちゃんと実行できていればコンソール上にHello world!が出力されているはずです。

簡単なCLIツールも作ってみましょう。任意の画像をPNGにするツールです。
完成品はこちら
ターミナルを開いて次のコマンドを実行してください。

$ cargo new example-cli
$ cd example-cli
$ cargo run

Hello, world!が出力されるはずです。

次に、clapというクレート(=ライブラリ)を追加しましょう。
ターミナルを開いて次を実行します。

$ cargo add clap --features derive

次に、コマンドラインの引数を解析するための構造体を定義します。

use clap::Parser;

#[derive(Parser)]
struct Cli {
    // 入力画像のパス
    input: String,
    // 出力画像のパス
    output: String,
}

これで下準備は完了です。

main関数をいじっていきましょう。
中身のprintln!()は削除し、色々書き換えていきます。

画像処理には、今回はimage-rs/imageを使います。

use image::ImageFormat;
use std::path::Path;
use std::process;

fn main() {
    // CLIの引数を解析
    let args = Cli::parse();

    // 画像を読み込む
    let img = match image::open(&args.input) {
        Ok(img) => img,
        Err(e) => {
            eprintln!("Error: {}", e);
            process::exit(1);
        }
    };

    // 出力先のパス
    let output_path = Path::new(&args.output);
    // 拡張子をpngに固定する
    let output = output_path.with_extension("png");

    // 画像を保存
    if let Err(e) = img.save_with_format(&output, ImageFormat::Png) {
        eprintln!("Error: {}", e);
        process::exit(1);
    }

    println!("Image saved to {}", output.display());
}

これで関数の部分は終了です。現在の状態は次のようになるかと思います。

use clap::Parser;
use image::ImageFormat;
use std::path::Path;
use std::process;

#[derive(Parser)]
struct Cli {
    // 入力画像のパス
    input: String,
    // 出力画像のパス
    output: String,
}

fn main() {
    // CLIの引数を解析
    let args = Cli::parse();

    // 画像を読み込む
    let img = match image::open(&args.input) {
        Ok(img) => img,
        Err(e) => {
            eprintln!("Error: {}", e);
            process::exit(1);
        }
    };

    // 出力先のパス
    let output_path = Path::new(&args.output);
    // 拡張子をpngに固定する
    let output = output_path.with_extension("png");

    // 画像を保存
    if let Err(e) = img.save_with_format(&output, ImageFormat::Png) {
        eprintln!("Error: {}", e);
        process::exit(1);
    }

    println!("Image saved to {}.png", output.display());
}

ビルドして実際に試していきましょう。

cargo run -- input.jpg output

正常に終了すれば、Runningの後に次のように表示されるはずです。

Image saved to output.png

これで一旦完成です。

まとめ

今回は極めてシンプルなCLIツールを作成しました。image-rsは他にも様々な拡張子に対応していますし、clapはより複雑なCLIもシンプルに作成できるため、色々いじって遊んでみてください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA