Rustは、高いパフォーマンスと安全性を持ちながら、システムプログラミングだけでなくWeb開発やファイル操作にも活用できる 言語です。
本記事では、Rustを使ったファイルの読み書き、HTTP通信、そして簡単なWebアプリの作成 について学んでいきます。
まず、std::fs を使ったファイルの読み書きと、効率的なバッファリングを行う BufReader・BufWriter の使い方 を解説します。
次に、reqwest を用いたHTTP通信と、serde によるJSONのシリアライズ・デシリアライズ を学び、RustでのAPI通信の基礎を理解します。
最後に、warp や actix-web などのWebフレームワークを活用し、簡単なWebサーバーを構築する方法 を実践します。
Rustは、高速で安全な並行処理を活かしながら、Web開発やネットワークプログラミングにも適した言語 です。
この章を通じて、Rustのファイル操作とWeb開発の基本を身につけ、より実用的なプログラムを開発するスキル を習得していきましょう!
ファイル操作
プログラムの実行中にデータを保存したり、外部ファイルから情報を読み取ることは多くのアプリケーションで必要になります。
Rustでは 標準ライブラリの std::fs を活用することで、簡単に ファイルの読み書き を行うことができます。
また、BufReader と BufWriter を利用することで、効率的なファイルの入出力処理 を実現できます。
この章では、std::fs を使った基本的なファイル操作の方法と、バッファリングを活用した最適なファイル処理 について学びます。
std::fsを使ったファイル読み書き
ファイルの読み込み
Rustでは std::fs::read_to_string や std::fs::File を使用して、簡単にファイルを読み込むことができます。
use std::fs;
fn main() {
let content = fs::read_to_string("example.txt")
.expect("ファイルの読み込みに失敗しました");
println!("ファイルの内容:\n{}", content);
}
1行ずつ読み込む方法
大量のデータを扱う場合、fs::read_to_string は メモリ使用量が大きくなる ため、File と BufReader を使うのが一般的です。
use std::fs::File;
use std::io::{self, BufRead};
fn main() -> io::Result<()> {
let file = File::open("example.txt")?;
let reader = io::BufReader::new(file);
for line in reader.lines() {
println!("{}", line?);
}
Ok(())
}
ファイルの書き込み
Rustでは、fs::write を使うと簡単にデータを書き込むことができます。
use std::fs;
fn main() {
fs::write("output.txt", "Rustでファイルに書き込み")
.expect("ファイルの書き込みに失敗しました");
println!("データを書き込みました");
}
追記モードで書き込む
fs::write ではなく、File を OpenOptions で開くことで 追記(append) することが可能です。
use std::fs::OpenOptions;
use std::io::Write;
fn main() {
let mut file = OpenOptions::new()
.append(true)
.create(true)
.open("output.txt")
.expect("ファイルのオープンに失敗しました");
writeln!(file, "新しい行を追加").expect("書き込みに失敗しました");
}
BufReaderとBufWriter
BufReader を使った効率的なファイル読み込み
BufReader は、ファイルを一度にすべて読み込むのではなく、バッファを使って部分的に読み込むことでパフォーマンスを向上させる ために使用されます。
use std::fs::File;
use std::io::{self, BufRead, BufReader};
fn main() -> io::Result<()> {
let file = File::open("large_file.txt")?;
let reader = BufReader::new(file);
for line in reader.lines() {
println!("{}", line?);
}
Ok(())
}
BufWriter を使った効率的なファイル書き込み
BufWriter を使うと、複数回の小さな書き込みをバッファにまとめ、まとめてディスクに書き込むことでパフォーマンスを向上 させることができます。
use std::fs::File;
use std::io::{self, Write, BufWriter};
fn main() -> io::Result<()> {
let file = File::create("buffered_output.txt")?;
let mut writer = BufWriter::new(file);
for i in 1..=5 {
writeln!(writer, "行 {}", i)?;
}
Ok(())
}
まとめ
std::fsを使うことで、Rustは簡単にファイルの読み書きを行うことができる。BufReaderはメモリ効率よくファイルを読み込むために使われる。BufWriterは頻繁な小さな書き込みをまとめ、パフォーマンスを向上させる。OpenOptionsを使うことで、既存のファイルへの追記が可能。
これで Rustのファイル操作の基本 を学びました。
RustでのHTTP通信
WebアプリケーションやAPIクライアントを開発する際、HTTP通信 は不可欠な要素です。
Rustでは reqwest を利用することで、シンプルにHTTPリクエストを送信し、レスポンスを受け取る ことができます。
また、APIのデータフォーマットとして広く使われる JSON の処理には serde を活用し、Rustの構造体と相互変換を行うことで、型安全なデータ処理が可能になります。
この章では、reqwest を使ったHTTPリクエストの基本操作と、serde によるJSONのシリアライズ(変換)・デシリアライズ(解析) について詳しく解説します。
reqwestを使ったHTTPリクエスト
reqwestとは?
reqwest は、RustでHTTP通信を行うためのライブラリであり、
以下のような機能を提供します。
GET,POST,PUT,DELETEなどのHTTPリクエストの送信- 非同期(async/await)対応のリクエスト処理
- JSONやテキストのレスポンス処理
- 認証・ヘッダーの追加などの高度なHTTP通信の管理
reqwest のインストール
Cargoプロジェクトで reqwest を利用するには、以下の依存関係を追加します。
[dependencies]
reqwest = { version = "0.11", features = ["json", "blocking"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
jsonを有効化すると、JSONの送受信が可能になる。blockingを有効化すると、同期(blocking)リクエストが利用可能。tokioは非同期処理(async/await)を利用する際に必要。
GETリクエストを送信する
Rustで reqwest を使い、外部APIからデータを取得する方法 を見てみましょう。
use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let response = reqwest::get("https://jsonplaceholder.typicode.com/posts/1")
.await?
.text()
.await?;
println!("レスポンス: {}", response);
Ok(())
}
コードのポイント
reqwest::get("URL")を使うと、GETリクエストを送信できる。awaitをつけることで、非同期処理として実行される。.text().await?を呼び出すと、レスポンスボディをStringとして取得できる。
POSTリクエストを送信する
データをAPIに送信する場合、POSTリクエスト を利用します。
use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let response = client.post("https://jsonplaceholder.typicode.com/posts")
.json(&json!({
"title": "Rust HTTP通信",
"body": "これはRustからのリクエストです。",
"userId": 1
}))
.send()
.await?
.text()
.await?;
println!("レスポンス: {}", response);
Ok(())
}
コードのポイント
Client::new()でHTTPクライアントを作成する。post("URL")を呼び出して、POSTリクエストを送信。.json(&json!({...}))を使うと、JSONデータを送信できる。
serdeを使ったJSONのシリアライズ
serde とは?
serde は、Rustのデータ構造(構造体など)とJSONを相互変換するライブラリ です。
API通信では、サーバーから送られてくるJSONデータをRustの型に変換したり、逆にRustのデータをJSONとして送信する場面が多くあります。
serde を活用することで、型安全にJSONの処理を行うことができます。
JSONのデシリアライズ(JSON → Rustの型)
サーバーから受け取ったJSONデータを Rustの構造体に変換する 方法を見てみましょう。
use reqwest;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Post {
userId: u32,
id: u32,
title: String,
body: String,
}
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let response = reqwest::get("https://jsonplaceholder.typicode.com/posts/1")
.await?
.json::()
.await?;
println!("受信したデータ: {:?}", response);
Ok(())
}
コードのポイント
#[derive(Deserialize)]を構造体に追加すると、JSONから自動でデータをマッピングできる。response.json::<Post>().await?を使うと、JSONデータをPost型に変換する。
JSONのシリアライズ(Rustの型 → JSON)
Rustのデータ構造を JSON文字列に変換する 方法を見てみましょう。
use serde::Serialize;
use serde_json;
#[derive(Serialize)]
struct User {
id: u32,
name: String,
email: String,
}
fn main() {
let user = User {
id: 1,
name: "Rustacean".to_string(),
email: "rust@example.com".to_string(),
};
let json_string = serde_json::to_string(&user).unwrap();
println!("JSONデータ: {}", json_string);
}
コードのポイント
#[derive(Serialize)]を構造体に追加すると、データをJSON形式に変換できる。serde_json::to_string(&user).unwrap()を使うと、Rustの型をJSON文字列に変換できる。
まとめ
reqwestを使うと、Rustで簡単にHTTPリクエストを送信できる。reqwest::get()でGETリクエスト、client.post()でPOSTリクエストを行える。serdeを活用することで、Rustの構造体とJSONを型安全に相互変換できる。#[derive(Deserialize)]でJSONからRustの型へ、#[derive(Serialize)]でRustの型からJSONへ変換可能。
これで Rustを使ったHTTP通信とJSONデータの処理 を学びました。
簡単なWebアプリの作成
Rustはシステムプログラミングだけでなく、Webアプリケーション開発にも適した言語 です。
非同期処理とメモリ安全性を強みとするRustは、高性能で安全なWebサーバーを構築するのに最適な選択肢 となります。
RustにはいくつかのWebフレームワークがありますが、本記事では特に人気の高い warp と actix-web を紹介します。
それぞれのフレームワークを利用して、簡単なWebサーバーを構築する方法 を学びます。
warpやactix-webを使ったWebサーバー構築
warpとは?
warp は、Rustの非同期ランタイム Tokio 上に構築された、軽量で柔軟なWebフレームワーク です。
以下のような特徴を持っています。
- 非同期処理に最適化されている(
async/awaitを活用) - 型安全なルーティングが可能
- フィルター(Filter)を活用した直感的なリクエスト処理
warpのインストール
Cargoの Cargo.toml に以下の依存関係を追加します。
[dependencies]
warp = "0.3"
tokio = { version = "1", features = ["full"] }
基本的なWebサーバーの作成
以下のコードは、シンプルなWebサーバーをwarpで構築する例 です。
use warp::Filter;
#[tokio::main]
async fn main() {
let hello = warp::path!("hello" / String)
.map(|name| format!("Hello, {}!", name));
warp::serve(hello)
.run(([127, 0, 0, 1], 3030))
.await;
}
コードのポイント
warp::path!("hello" / String)で/hello/{name}のリクエストを受け取るルートを定義する。map(|name| format!("Hello, {}!", name))でリクエストパラメータを取得し、レスポンスを返す。warp::serve(hello).run(([127, 0, 0, 1], 3030))でlocalhost:3030でサーバーを起動する。
このサーバーを実行し、以下のURLにアクセスすると、動作を確認できます。
http://localhost:3030/hello/Rust
→ レスポンス: Hello, Rust!
actix-webとは?
actix-web は、RustのWebフレームワークの中でも特に高性能でスケーラブルなWebアプリケーションを構築 できるフレームワークです。
以下のような特徴を持っています。
- マルチスレッド対応で高パフォーマンス
- 直感的なルーティング機能
- ミドルウェアによる柔軟な拡張性
actix-webのインストール
Cargoの Cargo.toml に以下の依存関係を追加します。
[dependencies]
actix-web = "4"
tokio = { version = "1", features = ["full"] }
基本的なWebサーバーの作成
以下のコードは、actix-web を使ったシンプルなWebサーバーの例 です。
use actix_web::{web, App, HttpServer, Responder, HttpResponse};
async fn greet(name: web::Path) -> impl Responder {
HttpResponse::Ok().body(format!("Hello, {}!", name))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/hello/{name}", web::get().to(greet))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
コードのポイント
async fn greet()で/hello/{name}のエンドポイントを定義する。web::Path<String>を引数に取ることで、URLパラメータを受け取る。HttpServer::new()で新しいWebサーバーを作成し、.bind(("127.0.0.1", 8080))でポート8080で起動する。
このサーバーを実行し、以下のURLにアクセスすると、動作を確認できます。
http://localhost:8080/hello/Rust
→ レスポンス: Hello, Rust!
まとめ
- RustのWebフレームワークには
warpとactix-webがあり、それぞれ異なる特徴を持つ。 warpは型安全なルーティングと非同期処理を活用したシンプルなフレームワーク。actix-webはマルチスレッド対応で高性能なWebサーバーを構築できる。- どちらのフレームワークも、シンプルなルート定義で簡単にWebサーバーを作成できる。
これで 第7回「ファイルとWeb開発」 の学習が完了しました。
次回の 第8回では「エコシステム活用」 について学びます。
Rustの強力なパッケージマネージャである Cargoの活用方法 や、人気のライブラリ、テスト・デバッグの手法を詳しく解説し、より実用的な開発環境を整えていきます!