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の活用方法 や、人気のライブラリ、テスト・デバッグの手法を詳しく解説し、より実用的な開発環境を整えていきます!