RustでWebアプリの実装にチャレンジしてみよう【準備編】:Webアプリ実装で学ぶ、現場で役立つRust入門(1)
Rustを使った「Webアプリ」の開発はどのようなものになるのでしょうか? 本連載のスタートとなる今回は、アプリ開発の下準備として、Rustの現状を踏まえた連載の目的を紹介し、Webアプリ開発環境の構築を通じて、Rustのプロジェクト管理の基本をおさらいします。
本連載のサンプルコードをGitHubで公開しています。こちらからダウンロードしてみてください。
本連載の目的
本連載は、@ITで2021年7月から連載された「基本からしっかり学ぶRust入門」(現在は完結)の応用編です。Rustは、当時から人気上昇中の言語と評価されていましたが、Stack Overflowが毎年実施している調査「Stack Overflow Developer Survey 2022」でも、変わらず「Rustが開発者の愛する言語」の1位に選ばれました。これは7年連続してのことです。この調査は、言語の好きと嫌いの差が大きいほど上位にランクされるので、Rustを嫌いな開発者は少数、という見方ができます。また、「これから使いたい言語」の1位も獲得しているようで、少なくとも開発者の間では今後も支持を伸ばしていきそうな言語と言えます。
Rustは美点の多いマルチパラダイム言語
Rustの美点は多岐にわたり、ネイティブコードコンパイラによる高速な実行バイナリ、所有権と借用の仕組みによる安全なメモリ管理、言語そのものに単体テストやパッケージ管理の仕組みを導入していることなど、枚挙にいとまがありません。C/C++を置き換えられるシステムプログラミングのための言語であり、オブジェクト指向型のプログラミング言語でもあり、ジェネリックプログラミングが可能で関数型プログラミング言語の一面も持ち合わせるなど、マルチパラダイムなプログラミング言語としての性質を持っています。
Rustは多くの場所で使われている
このように人気があり性能評価の高いRustですが、実際のところ誰がどのような分野で使っているのでしょうか。開発に携わったMozillaは当然として、Amazon、Google、Microsoft、Oracleなどのクラウドベンダー、MetaやDropboxが自身のプロダクトの開発にRustを使用している、利用することを表明しています。
AWS Lambdaでは早くからRustのサポートをはじめており、Lambdaをはじめとする多くの基盤でRustを利用しています。GoogleはAndroidアプリ開発にRustを導入することを表明していますし、MicrosoftがWindowsの開発にRustを導入しているのは有名です。仮想通貨ETHのブロックチェーンであるイーサリアムのステーキングに使うアプリケーションLighthouseはRustで実装されています。
Linuxでは、以前からカーネル開発にRustを導入することを表明してきましたが、2022年12月にリリースされたLinuxカーネル6.1で、はじめてRustで記述されたコードが採用されました。2023年2月にはカーネル6.2がリリースされ、同年4月にリリースされたUbuntu 23.04に搭載されました。これにより、身近なディストリビューションでRustによるカーネル開発の一端を試してみることが可能になっています。並行して、Rust for LinuxプロジェクトでデバイスドライバなどのモジュールをRustで記述する環境が整ってきています。
RustとWeb開発
上記のような状況ではありますが、RustにはRubyにおけるRailsのようなキラープロダクツがない、と言われます。RailsがRuby開発者の裾野を拡げたように、Rustにもそのようなプロダクトの登場を心待ちにする声もあるようです。上記の事例のように確実に普及は進んでいますが、それらは主にシステムプログラミングの分野であり、誰にも見えて触れるというようにはなっていないということのようです。
となると、やはりWeb開発の分野で使える、使われるようになると一気に普及するのではないか?と思うのは筆者だけではないはずです。Rustは、見方を変えれば何でもできる(書ける)言語であるので、後は優れたフレームワークが登場すれば、潜在ユーザーの多いRustであるだけに名実ともに表舞台に躍り出る、ということが期待できそうです。
実際、堅牢(けんろう)性に優れたRustをWeb開発に導入しようという動きは活発なようで、多数のフレームワーク、例えばサーバサイドのactix-web、Axum、クライアントサイドのDioxusなどがすでにリリースされています。特にクライアントサイドではWebAssemblyのサポートでRustのメリットを十分に生かすことができるというメリットがあります(@ITの記事RustでWebAssembly――「Rust and WebAssembly」を体験するを参照)。
本連載ではここに焦点を当て、RustのためのWebアプリフレームワークactix-web、UIフレームワークDioxusなどを取り上げながら、「RustでWebアプリを作るとどうなるのか?」という視点で実用的なアプリケーションを開発し、開発現場で役に立つ知識、技法を紹介していきます。
Webアプリ実装に向けての環境構築
ここからはWebアプリ実装に向けての環境を構築していきましょう。まずはRust自身のインストールです。インストールは非常に簡単で、下記のページの指示に従うだけでインストールを実施できます。
本記事では、macOSとWindowsにおけるRustのインストール方法を紹介します(LinuxについてはmacOSとほぼ同様の手順になります)。
macOSでRustをインストールする
macOSの場合は、「Rust をインストール」ページに表示されているコマンドを、ターミナルを開いて実行します(図1)。
% curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh …略… 1) Proceed with installation (default) 2) Customize installation 3) Cancel installation
シェルスクリプトがダウンロードされて実行されます。ズラッと長いメッセージが表示されて選択待ちとなります。メッセージは、インストールで行われる処理の内容です。これらに納得してインストールをはじめることになるので、よく目を通しておきましょう。表示されている内容を表にまとめると、表1のようになります($HOMEはログインユーザーのホームを意味する。/Users/naoなど)。
項目 | 内容 |
---|---|
Rustツールチェインやメタデータの置き場所 | $HOME/.rustupフォルダ(環境変数RUSTUP_HOMEがあれば、これが使われる) |
Rustのパッケージマネジャーのためのフォルダ | $HOME/.cargoフォルダ(環境変数CARGO_HOMEがあれば、これが使われる) |
環境変数PATHの編集対象 | $HOME/.profileファイル、$HOME/.bash_profileファイル、$HOME/.zshenvファイル |
インストールオプション | プラットフォームはx86_64-apple-darwin、既定のツールチェインはstable(安定版)、プロファイルはdefault、環境変数の編集はyes(あり) |
表1:Rustのインストール情報(macOS) |
Rustのコマンド類は、$HOME/.cargo/binフォルダに置かれます。$HOME/.rustupフォルダにもtoolchains/stable-x86_64-apple-darwin/binフォルダといったものがありますが、こちらはあくまでもrustupによる管理用です。実際に使われるのは$HOME/.cargo/binフォルダのコマンドであり、こちらが環境変数PATHに設定されることを覚えておきましょう。
インストールするバージョンなどを変更したい場合には「2) Customize installation」を選択しましょう。ここではデフォルトの「1) Proceed with installation (default)」のまま進めました。
info: profile set to 'default' info: default host triple is x86_64-apple-darwin …略… Rust is installed now. Great! To get started you may need to restart your current shell. This would reload your PATH environment variable to include Cargo's bin directory ($HOME/.cargo/bin). To configure your current shell, run: source "$HOME/.cargo/env"
「Great!」というように太字で表示されればインストールは成功です。最後に表示されているように、source $HOME/.cargo/envコマンドを実行すれば環境変数PATHへの反映はすぐに実行されます。
WindowsでRustをインストールする
Windowsの場合、インストーラであるrustup-init.exeのダウンロードになります(図2)。インストーラには32bit版と64bit版がありますが、Windows 11では「RUSTUP-INIT.EXE(64-BIT)をダウンロードする」を選択しましょう(Windows 10以前では、OSに合ったものを選択)。なお、WSL(Windows Subsystem for Linux)用のインストールコマンドも表示されますが、これは基本的にはmacOS、Linux用と同じです。WSLを使いたいという場合には、こちらの方法を選択しても良いでしょう。
インストーラrustup-init.exeを実行すると、ターミナルが開きます。このとき、Microsoft C++ Build Toolsがインストールされていないと、それをインストールせよと指摘されます(図3)。この画面が出たら、先に進む前にMicrosoft C++ Build Toolsのインストールが必要です。
Microsoft C++ Build Toolsのインストール方法は2つあります。Visual Studio(2013以降)を使っているなら、Visual Studio Installerを使って[ワークロード]タブから「C++によるデスクトップ開発」にチェックを入れ、「MSVC v143 - VS 2022 C++ x64/x86 ビルドツール」(Visual Studio 2022の場合)などをインストールしてしまうのが簡単です(図4)。このとき、[言語パック]タブに切り替えて「英語」にチェックを入れておきます。英語パックが必要なのは、Rustが英語ロケールを使用するためです。
この方法は簡単ですが、Visual Studioそのものや、C++によるデスクトップ開発の機能が不要な場合には、ディスク領域とインストール時間のムダです。この場合には次に紹介するMicrosoft C++ Build Toolsの単体インストールをおすすめします。
Microsoft Visual C++ Build Toolsを単体でインストールするには、以下の「Microsoft C++ Build Tools - Visual Studio」のページから「Build Toolsのダウンロード」をクリックします(図5)。
Microsoft C++ Build Tools - Visual Studio
インストーラvs_BuildTools.exeを実行すると、Visual Studio Installerが構成されて起動します(図6)。
図6の右ペイン「インストールの詳細」に「MSBuild Tools」と表示されていることを確認して、[言語パック]タブに切り替えて「英語」にチェックを入れておきます。英語パックが必要なのは、Rustが英語ロケールを使用するためです。
ここで、[インストール]をクリックするとMicrosoft C++ Build Toolsのインストールが始まります。図8のように、[インストール済み]タブに「Visual Studio Build Tools 2022」などと表示されればインストールは成功です。筆者はVisual Studioを利用中ですが、ディスク容量節約のためにあえて単体でインストールしてみました。
「Microsoft C++ Build Tools」のインストールを済ませたら、図3で「Continue?」に対して「y」を入力して先に進めましょう。ズラッと長いメッセージが表示されて選択待ちとなります。メッセージは、インストールで行われる処理の内容です。これらに納得してインストールをはじめることになるので、よく目を通しておきましょう。表示されている内容を表にまとめると、表2のようになります(%HOME%はログインユーザーのホームを意味する。\Users\naoなど)。
項目 | 内容 |
---|---|
Rustツールチェインやメタデータの置き場所 | %HOME%\.rustupフォルダ(環境変数RUSTUP_HOMEがあれば、これが使われる) |
Rustのパッケージマネジャーのためのフォルダ | %HOME%\.cargoフォルダ(環境変数CARGO_HOMEがあれば、これが使われる) |
環境変数PATHの編集対象 | レジストリキーHKEY_CURRENT_USER/Environment/PATH |
インストールオプション | プラットフォームはx86_64-pc-windows-msvc、既定のツールチェインはstable(安定版)、プロファイルはdefault、環境変数の編集はyes(あり) |
表2:Rustのインストール情報(Windows) |
Rustのコマンド類は、%HOME%\.cargo\binフォルダに置かれます。%HOME%\.rustupフォルダにもtoolchains\stable-x86_64-pc-windows-msvc\binフォルダといったものがありますが、こちらはあくまでもrustupによる管理用です。実際に使われるのは%HOME%\.cargo\binフォルダのコマンドであり、こちらが環境変数PATHに設定されることを覚えておきましょう。
インストールするバージョンなどを変更したい場合には「2) Customize installation」を選択しましょう。ここではデフォルトの「1) Proceed with installation (default)」のまま進めました(図9)。「Great!」と出ればインストールは終わりです。[Enter]キーを押してコマンドプロンプトを閉じます。%HOME%\.cargo\binフォルダの環境変数PATHへの設定は、レジストリを書き換えることで自動的に実行されます。
Rustのインストール状況を確認する
macOS、Windowsともに、Rustのインストール状況は以下のように確認します(例はmacOS)。この場合はcargoコマンドを実行しましたが、rustcコマンドなどでも同様のバージョンになるはずです。
% cargo --version cargo 1.72.0 (103a7ff2e 2023-08-15)
Rustをアンインストール、アップデートする
Rustのアンインストールは、macOS、Windowsともにrustup self uninstallコマンドを実行します。「Continue? (y/N)」に対してyで応答すれば、$HOME/.rustupと$HOME/.cargo(macOSなど)あるいは%HOME%\.rustupと%HOME%\.cargo(Windows)からプログラムが除去され、実行パスが環境変数から取り除かれます。
アップデート版があれば、rustup updateコマンドで更新できます。
Rustのプロジェクト管理
最後は、Rustのプロジェクト管理をおさらい、体験しましょう。第2回以降から、プロジェクトを作成してフレームワークを導入したり、モジュールに分かれたコードを利用していくことになりますから、ここでその概要を示しておきます。作成するプロジェクトは、シンプルなWebサーバのアプリケーションです。GETリクエストを受け付けてファイルを返すだけというシンプルなものですが、関数をモジュールに分離したり外部のクレートを利用したりして、できるだけ実践に近い形にしています。
なお、プロジェクト、パッケージ、クレート、モジュールといった用語が登場しますが、これらについては前連載の第12回で詳しい解説がありますので、できれば一読しておくことをおすすめします。
プロジェクトを作成する
Rustでは、Cargoパッケージマネジャーという単体のツールで、プロジェクト管理のほとんどのことを済ますことができます。プロジェクトの作成は、cargo newコマンドです。
% cargo new http-server
プロジェクトのためのhttp-serverフォルダが作成され、ソースファイルを格納するsrcフォルダ、プロジェクト管理のためのファイルであるCargo.tomlが生成されます。そしてsrcフォルダには、プログラムのエントリポイントであるmain.rsファイルが置かれます。main.rsファイルにはmain関数が定義されており、"Hello, world!"を出力するコードが既定で置かれています。
エントリポイントを書き換える
エントリポイントであるmain.rsファイルの内容を、以下のリストの内容で置き換えます。これは、TcpListenerを使ってポート8080番でリクエストを待ち受けて、リクエストがあればsubモジュールにあるtcp_handler関数をスレッドを起動して呼び出すだけの処理になっています。これらの処理に必要なモジュールは標準ライブラリに含まれるので、use文をおのおの記述するだけで利用できます。
use std::io::Result; use std::net::TcpListener; use std::thread; mod sub; fn main() -> Result<()> { let listener = TcpListener::bind("0.0.0.0:8080")?; while let Ok((stream, _)) = listener.accept() { thread::spawn(|| sub::tcp_handler(stream)); } Ok(()) }
別クレートにモジュールを作成する
main.rsでは、main関数からsubモジュールのtcp_handler関数を呼び出していました。ここで、モジュールを作成し、そこにtcp_handler関数を記述します。モジュールの作成は、別のクレートを作成するだけです。プロジェクトのsrcフォルダに、sub.rsファイルを作成し、以下のリストの内容とします。コードの内容の細かな説明は省きますが、リクエストから正規表現処理で目的のパスを取得し、そのファイルがあればレスポンスで返すというものです。Rustは標準では正規表現処理を持たないので、外部クレートregexを参照しています。
use std::{ path::Path, fs::read_to_string, io::{Result, Read, Write}, net::TcpStream, }; use regex::Regex; pub fn tcp_handler(mut stream: TcpStream) -> Result<()> { let mut buffer = [0; 1024]; stream.read(&mut buffer)?; let re = Regex::new(r"^GET /([a-zA-Z\d\.\-/_]+) HTTP/1\.1").unwrap(); let response = match re.captures(&String::from_utf8(buffer.to_vec()).unwrap()) { Some(caps) => { let path = Path::new(&caps[1]); if path.is_file() { let status_line = "HTTP/1.1 200 OK"; let html = read_to_string(path)?; let http_header = format!( "Content-Length: {}\r\nContent-Type: text/html;charset=UTF-8", html.len() ); format!("{}\r\n{}\r\n\r\n{}", status_line, http_header, html) } else { "HTTP/1.1 404 Not Found\r\n\r\n".to_string() } }, None => { "HTTP/1.1 400 Bad Request\r\n\r\n".to_string() }, }; stream.write_all(response.as_bytes())?; stream.flush() }
外部クレートを参照する
sub.rsのコードでは正規表現を扱うregexクレートが使われています。これはプロジェクト外部にあるので、http-serverプロジェクトがregexクレートに依存することを知らせてあげる必要があります。これには、cargo addコマンドを使います。
% cargo add regex
この結果は、プロジェクトのCargo.tomlファイルに反映されます。つまり、ファイルを直接書き換えてもOKですが、cargo addコマンドでは最新バージョンを探して設定してくれるので、コマンドを使う方が便利でしょう。
…略… [dependencies] regex = "1.9.5"
まとめ
今回は、本連載の目的を紹介し、Webアプリ開発環境の構築を通じて、Rustのプロジェクト管理の基本をおさらいしました。
次回は、Webアプリのサーバサイドのフレームワークであるactix-webを紹介し、簡単な投稿型アプリケーションを実装していきます。
筆者紹介
WINGSプロジェクト
有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティー(代表山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手掛ける。2021年10月時点での登録メンバーは55人で、現在も執筆メンバーを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。
・サーバーサイド技術の学び舎 - WINGS(https://wings.msn.to/)
・RSS(https://wings.msn.to/contents/rss.php)
・X: @WingsPro_info(https://x.com/WingsPro_info)
・Facebook(https://www.facebook.com/WINGSProject)
Copyright © ITmedia, Inc. All Rights Reserved.