気楽に Rust で遊びたい Script 感覚で始める Rust
はじめに
僕は Rust がとてもすきです。
でも型の制約はキツイし、なんだか覚えることがたくさんあるぞ……
TypeScript でよく適当なツールを書いてるのですが、そのくらいの気軽さで Rust で遊べないかな?と思い試してみました。
TypeScript でいう以下の機能が使えたらよさそうですね!
- fetch
- JSON.stringify
- JSON.parse
- console.log
- fs.writeFile
- fs.readFile
Rust の install
まずは Rust と cargo を install します。
すでに install されている場合はスキップしてください。
公式 にある通り shell でこれを実行してみましょう。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Rust の環境構築
続いて作業環境を作ります。
npm init みたいなものですね。
mkdir project
cd project
cargo init
nodemon のようにファイルの変更があれば再起動するツールもほしいですね。
グローバルに install しておきましょう。
cargo install bacon
準備が整いました。
console.log 的なことを試す
すでに src/main.rs が作られているので触ってみましょう。
fn main() {
println!("Hello, world!");
}
cargo run で実行できます。
bacon を global に install していれば bacon run でファイルの変更があれば再起動できます。
ターミナルに Hello, world! が表示されましたか?
続いて world を work に変更し、保存して再実行してみましょう。
僕らが進むべき道がターミナルに表示されます。
Github api を叩いてみよう
module を install
必要なものを install してみましょう。
- reqwest(blocking)
- 同期的に http request する
- serde, serde_json
- JSON の serialize/deserialize をする
tokio を使えば非同期(async/await)が使えますが、今回は同期で作ってみましょう。
cargo add reqwest --features blocking
cargo add serde
cargo add serde_json
これまでの作業で Cargo.toml が以下のようになっていれば OK です。
[package]
name = "project"
version = "0.1.0"
edition = "2024"
[dependencies]
reqwest = { version = "0.12.23", features = ["blocking"] }
serde = "1.0.219"
serde_json = "1.0.143"
src/types.rs を作る
別ファイルにあるものを import したくなることがよくあるので import/export 方法を押さえておきましょう。
src/types.rs を作り次のコードを記述しましょう。
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Config {
pub url: String,
pub user_agent: String,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct GitHubUser {
pub login: String,
pub id: u64,
pub public_repos: u32,
}
pub をつけておくと別のファイルからも参照できるようになります。
use でライブラリを import することができます。
先程も軽く触れましたが serde は JSON の serialize/deserialize をするライブラリです。
#[derive(Debug, Deserialize, Serialize)] をつけておくといい感じにマッピングしてくれます。
#[serde(rename_all = "camelCase")] があると JSON 内ある camelCase を snake_case に変換してくれます。
config.json を作成
url と user_agent を設定する config を project 直下に作りましょう。
以下の内容を config.json というファイル名で保存してください。
{
"url": "https://api.github.com/users/rust-lang",
"userAgent": "project/0.1.0"
}
src/main.rs を上書きする
いよいよ実行するコードを書いていきます!
src/main.rs を次のコードに上書きしてみてください。
mod types;
use reqwest::blocking::Client;
use std::fs::{read_to_string, write};
use types::{Config, GitHubUser};
fn main() {
let config_str = read_to_string("config.json").unwrap();
let config: Config = serde_json::from_str(&config_str).unwrap();
let client = Client::builder()
.user_agent(&config.user_agent)
.build()
.unwrap();
let response = client.get(&config.url).send().unwrap().text().unwrap();
let user: GitHubUser = serde_json::from_str(&response).unwrap();
println!("GitHub User Info:");
println!("- Login: {}", user.login);
println!("- ID: {}", user.id);
println!("- Public Repos: {}", user.public_repos);
let output = serde_json::to_string_pretty(&user).unwrap();
write("output.json", output).unwrap();
}
流れは次のようになっています。
- project にある config.json を読み込む
- config に設定してある user_agent と url を使って github の API を叩く
- response を JSON に deserialize する
- deserialize した JSON を出力する
- deserialize した JSON を output.json に書き出す
実行
実行してみましょう。
cargo run は cargo r でも実行できます。
ターミナルに次のように表示されたはずです。
> cargo r
Blocking waiting for file lock on build directory
Compiling project v0.1.0 (/Users/h/h/rust-scriptsy)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.77s
Running `target/debug/project`
GitHub User Info:
- Login: rust-lang
- ID: 5430905
- Public Repos: 231
project 直下に output.json が出力されているのでその内容も見てみましょう。
{
"login": "rust-lang",
"id": 5430905,
"public_repos": 231
}
まとめ
今回は気楽に動かしたいので unwrap を使いまくってます。
本番環境でやったら恨まれるのでやめましょう。
ここまでできたらいろんなアイディアが試せそうですね!
Rust を楽しんでいきましょう〜〜〜
Discussion