サンプルコード
Rust のサンプルコード一覧
Rust で「○○するには」を解決するコードサンプル。73 件。
他の言語から探す
2つの日付の差を求めるには
標準ライブラリにはカレンダー上の日付型が無いため、日付の差を取るには `chrono` を使う。`NaiveDate` 同士の引き算は `TimeDelta` を返し、`num_days()` で日数を取り出す。タイムゾーンを持たせたい場合は `NaiveDate` ではなく `DateTime<Tz>` 側を使う。
配列を条件で絞り込むには
イテレータの `filter` は遅延評価なので、`collect` を呼ぶまで何も走らない。`iter` は参照を返すため、値の `Vec` が欲しいときは `copied` や `cloned` を挟んでから集める。
環境変数を削除するには
edition 2024 では `std::env::remove_var` が `unsafe` になっており、`unsafe` ブロックなしで呼ぶと E0133 でビルドが止まる。他のスレッドが環境を読んでいる最中に書き換えるとデータ競合になりうるためである。子プロセスから外すだけなら `Command::env_remove` が安全な方法で、自プロセスの環境は触らずに済む。
QRコードを生成するには
標準ライブラリに QR コードの生成が無いので、`qrcode` と `image` の 2 つのクレートを使う。`render::<Luma<u8>>()` で白黒の画像にし、`min_dimensions` で下限の大きさを指定すると、1 モジュールが整数ピクセルになる大きさへ切り上がる。
ディレクトリ内のファイル一覧を取得するには
`fs::read_dir` はイテレータを返し、各要素が `Result` になる。項目ごとに失敗しうるので `filter_map` で取りこぼしを落としてから判定する。`file_name()` は `OsString` なので、表示するときに `to_string_lossy()` で文字列へ移す。
ネストしたJSONから値を取り出すには
`serde_json` の `pointer` は JSON Pointer(RFC 6901)形式のパスで一気に辿れる。戻り値は `Option` なので、`as_u64` や `as_str` で型を確かめてから `unwrap_or` で既定値に倒す。構造が決まっているなら `Value` ではなく `Deserialize` 付き構造体の方が安全である。
乱数のシードを固定して同じ結果を再現するには
標準ライブラリには乱数がないので `rand` クレートを使う。`StdRng::seed_from_u64` でシードから生成器を作り、`random_range` で範囲を指定して値を取り出す。
HTTPリクエストにヘッダーを付けるには
reqwest では header をメソッドチェーンで重ねる。ACCEPT のような定数が用意されているヘッダーはそちらを使うと綴り間違いを型検査で防げる。
配列からランダムに1つ選ぶには
`rand` クレートの `IndexedRandom` トレイトを `use` すると、スライスとベクタで `choose` メソッドが使える。戻り値は `Option` で、空なら `None` になるので、添字の範囲外で panic することがない。
ランダムな文字列を生成するには
標準ライブラリに乱数は無いため、`rand` クレートを `Cargo.toml` に追加する。`sample_iter(&Alphanumeric)` で英数字 62 種類から 1 文字ずつ取り出し、`take(16)` で長さを決めて `String` にまとめる。0.10 系では `sample_iter` を呼ぶのに `RngExt` トレイトの `use` が要る。`rand::rng()` は OS から種を得る暗号論的擬似乱数として設計されている。
環境変数を設定するには
edition 2024 で std::env::set_var と remove_var は unsafe になった。他スレッドが getenv を呼んでいる最中に環境を書き換えるとデータ競合になりうるためで、呼ぶ側がシングルスレッドであることを保証する責任を負う。子プロセスへ渡すだけなら Command::env で足りるので、そちらを優先するとよい。`unsafe` を付けずに呼ぶと、E0133(`call to unsafe function set_var is unsafe and requires unsafe block`)でビルドが止まる。
UUIDを生成するには
標準ライブラリに UUID は無いため、`uuid` クレートを使い、`Cargo.toml` で `v4` と `v7` の feature を有効にする。feature を付けないと、`Uuid::new_v4` が見つからないというコンパイルエラー(E0599)になる。ハイフンなしの文字列は `simple()` で得る。
範囲を指定して乱数を得るには
標準ライブラリに乱数は無いため、`rand` クレートを `Cargo.toml` に追加して使う。0.10 系では `random_range` を呼ぶのに `RngExt` トレイトの `use` が要り、忘れるとメソッドが見つからないというコンパイルエラー(E0599)になる。範囲は `1..=6` なら上限を含み、`1..7` なら含まない。
配列をランダムに並べ替えるには
`rand` クレートの `SliceRandom` トレイトを `use` すると、スライスやベクタで `shuffle` メソッドが使える。引数には `rand::rng()` が返す乱数生成器を `&mut` で渡す。元のベクタを直接並べ替える。
.env ファイルを読み込むには
dotenvy はメンテナンスが止まった dotenv クレートの後継である。`dotenv()` は `Result` を返すので、.env を必須にしないなら `ok()` で握りつぶす。読み込み後は `std::env::var` で通常どおり取り出せ、既存の環境変数は上書きされない(`PORT=1111` を付けて起動すると 1111 が出力された)。
文字列のSHA-256ハッシュ値を求めるには
標準ライブラリに SHA-256 は無いため、`sha2` クレートを `Cargo.toml` に追加して使う。`Sha256::digest` は 32 バイトの結果を返し、`{:x}` の書式でそのまま 16 進数の文字列として出力できる。分けて渡すときは `Sha256::new()` に `update` を重ね、`finalize` で取り出す。
文字列が含まれるか調べるには
`str::contains` は `Pattern` を受け取るため、&str だけでなく `char` や「`char` を判定するクロージャ」も渡せる。大文字小文字は既定で区別するので、無視したいときは `to_lowercase` で新しい `String` を作ってから判定する。位置が必要なときの `find` は -1 ではなく `Option<usize>` を返す。
日付をJSON文字列にするには
`chrono` は `serde` feature を有効にすると `DateTime` を RFC 3339 の文字列として `Serialize` / `Deserialize` できる。feature を付け忘れると、`DateTime<FixedOffset>` に `Serialize` が実装されていないという `E0277` のコンパイルエラーになる。
日付文字列を日付型にするには
標準ライブラリに日付の書式解析は無いので chrono を使う。タイムゾーンを持たない値は `NaiveDate` / `NaiveDateTime`、オフセット付きの文字列は `DateTime::parse_from_rfc3339` で受ける。いずれも `Result` を返すため、`unwrap` で潰さず `match` や `?` で失敗を扱うと入力エラーをそのまま呼び出し元へ伝えられる。
配列から重複を除くには
`HashSet::insert` は新規挿入のときだけ `true` を返すので、`filter` と組み合わせると初出だけが残り出現順を保てる。`Vec::dedup` は連続した重複しか除去しないため、そちらを使うなら先に `sort` する必要があり、出現順は失われる。
正規表現の特殊文字をエスケープするには
`regex::escape` は `regex` クレートの関数で、特殊文字の前に `\` を付けて返す。`Regex::new` は不正なパターンに `Err` を返すので、外から来た文字列は `regex::escape` に通してから渡す。置換文字列の `$name` は展開され、存在しない名前は空になるため、そのまま入れたいときは `NoExpand` で包む。
文字列の前後の空白を除去するには
`str::trim` は前後の空白を落とした部分文字列(`&str`)を返すため、新しい `String` は確保されない。全角スペース(U+3000)も空白として落ちる。特定の文字を落とすなら `trim_matches` に `char`、`char` のスライス、クロージャを渡す(`&str` を渡すとコンパイルエラーになる)。接頭辞を外す `strip_prefix` は一致しなければ `None` を返すので、外れたかどうかを戻り値で判定できる。
ホームディレクトリのパスを取得するには
`env::home_dir()` は `HOME` を優先し、無ければ passwd のホームを返す。戻り値が `Option<PathBuf>` なので、サンプルでは取れなかったときに `expect` で止めている。ファイル API の `Path::exists` は `~` を展開せず、`~` という名前を探すだけなので `false` になる。
HTTP POSTでJSONを送るには
`reqwest` の `json()` は本文のシリアライズと `Content-Type` の付与をまとめて行うため、ヘッダを手で書く必要がない。`error_for_status()` を挟むのは、4xx / 5xx を `Err` に変換してエラー応答を作成結果として読み進めないようにするためである。`json` 機能を有効にしないとこのメソッドは使えず、コンパイル時に `no method named json found` のエラーになる。実行すると `101` と表示される。
ファイルを読み込むには
fs::read_to_string はファイル全体を String として読み込む。String は UTF-8 であることが保証された型なので、UTF-8 として正しくないバイトが含まれていると文字化けした文字列を返すのではなく、ErrorKind::InvalidData の Err になる。? 演算子はそのエラーを呼び出し元へ伝播するため、main を含む関数の戻り値を Result にしておく必要がある。
整数を2進数や16進数の文字列にするには
書式指定の `{:b}` `{:o}` `{:x}` で文字列にし、`from_str_radix(text, radix)` で戻す。接頭辞付きにするには `{:#x}` と書く。負の数は 2 の補数のビット列になるほか、`from_str_radix` は `0x` を読めず `InvalidDigit` を返すため、先に `trim_start_matches` で取り除く。
JSONをパースするには
Rust の標準ライブラリに JSON パーサは無いため、serde と serde_json をクレートとして追加する。derive(Deserialize) を使うには serde の derive フィーチャーが要るので、cargo add serde --features derive で追加する。構造体にあるフィールドが JSON に無いと、コンパイル時ではなく実行時に missing field の Err になる。JSON 側の余分なキーは既定で無視される。
オブジェクトをJSON文字列にするには
標準ライブラリに JSON は含まれないため、`serde` と `serde_json` をクレートとして追加する。`to_string` が 1 行、`to_string_pretty` が整形版で、どちらも `Result` を返す。`derive(Serialize)` を付けていない型を渡すと、`the trait bound … is not satisfied`(E0277)でコンパイルが止まる。
JSONをファイルに保存するには
serde_json::to_writer_pretty で BufWriter 越しに一時ファイルへ書き、flush してから fs::rename で置き換える。BufWriter は drop のときに残りを書き出すが、そこで起きたエラーは捨てられるので、flush を明示して Result を受け取る。serde と serde_json は標準ライブラリに無いため、cargo add serde --features derive と cargo add serde_json で依存に加える。
バイト列を16進数の文字列にするには
標準ライブラリには 16 進数の変換関数が無いため、この例では `format!` と同じ書式指定の `{:02x}` で 1 バイトずつ 2 桁にそろえて連結した。戻すときは 2 文字ずつ `u8::from_str_radix(…, 16)` で読み、不正な文字は `Err` になる。
配列を文字列に連結するには
&str や String のスライスには join が生えており、戻り値は String になる。数値のベクタには直接使えないので、to_string でいったん文字列へ写してから連結する。
文字列を分割するには
`str::split` はイテレータを返すため、配列として扱いたいときは `collect` でまとめる。元の文字列を借用した `&str` のスライスが返るだけなので、コピーは発生しない。要素数を絞るなら `splitn`、空白区切りなら `split_whitespace` を使う。
文字列をUTF-8のバイト列にするには
Rust の `str` も UTF-8 で保持されており、`as_bytes` でそのままバイト列として借りられる。バイト列から `str` に戻す `std::str::from_utf8` は不正だと `Err` を返し、`String::from_utf8_lossy` なら U+FFFD に置き換えて通す。文字数は `chars().count()` で数え、`len` はバイト数である。
文字列をBase64にするには
標準ライブラリに Base64 の関数は無いため、base64 クレートを Cargo.toml に追加して使う。0.22 系では用途ごとの engine(STANDARD・URL_SAFE・URL_SAFE_NO_PAD など)を選び、encode と decode を呼ぶ。Engine トレイトを use しないと、encode メソッドが見つからないというコンパイルエラー(E0599)になる。
ファイルの文字コードを変換するには
標準ライブラリには Shift_JIS の変換が無いため、encoding_rs クレートの SHIFT_JIS.decode を使う。戻り値の 3 つ目の had_errors が、変換できないバイトを U+FFFD に置き換えたかどうかを示す。Rust の文字列は常に UTF-8 なので、as_bytes をそのまま書き出せば UTF-8 のファイルになる。
HTMLの特殊文字をエスケープするには
標準ライブラリに HTML エスケープの関数は無いため、文字ごとに match で置き換える関数を書く。1 文字ずつ新しい String へ書き出すので、& の置換順を気にしなくてよい。依存クレートを増やさずに済むのも利点である。
HTTP GETリクエストを送るには
標準ライブラリに HTTP クライアントが無いため、Rust では reqwest のような外部クレートを入れるのが前提になる。error_for_status() を挟むのは、4xx / 5xx を Err に変換して本文をそのまま読み進めないようにするためである。本文の先頭だけ出すときは、バイト位置の範囲指定ではなく chars().take(n) で文字単位に切る。
文字列をURLエンコードするには
標準ライブラリに URL エンコードの関数が無いため、urlencoding クレートを Cargo.toml に追加して使う。encode は英数字と - _ . ~ 以外をすべて変換するので、値の部分にそのまま使える。依存を書き忘れると E0433 で解決できない。
日付を書式付きの文字列にするには
標準ライブラリにはカレンダー上の日付を書式化する機能が無いため、chrono クレートを依存に加えるのが一般的である。with_ymd_and_hms は存在しない時刻(夏時間の間隙など)を考慮して LocalResult を返すので、受け取り側で展開が必要になる。
文字列の長さを取得するには
str::len は UTF-8 のバイト数を返し、文字数は chars().count() で求める。chars().count() は先頭から走査するので文字列の長さに比例した時間がかかる。見た目の 1 文字(書記素クラスタ)で数える機能は標準ライブラリに無く、unicode-segmentation クレートなどを使う。
ファイルが存在するか調べるには
Path::is_file は内部でメタデータを取得し、取得できなければ false を返す。存在しないのか権限が無いのかを区別したい場合は、fs::metadata の Result を直接見て、エラーの kind が NotFound か PermissionDenied かで分ける。
UNIXタイムスタンプを日付に変換するには
標準ライブラリはカレンダー上の日付を扱えないため、chrono クレートを使う。DateTime::from_timestamp は表せない範囲の値に対して None を返すので Option で受け取り、ミリ秒の値は from_timestamp_millis に渡す。
配列に要素が含まれるか調べるには
スライスの contains は要素への参照を受け取るので、&"banana" のように参照で渡す。Vec<String> に &"bob"(&&str 型)を渡すと、期待される &String と合わずコンパイルエラー(E0308)になるため、iter().any で比べるか、String を作って渡す。
現在時刻を取得するには
標準ライブラリの SystemTime はエポックからの経過時間しか扱えず、年月日への変換や書式化の機能を持たない。カレンダー上の日時が必要なら chrono や time クレートを依存に追加する。
ディレクトリを作成するには
fs::create_dir は親が無いと NotFound、既にあると AlreadyExists で失敗する。通常は親までまとめて作り、既にディレクトリがあれば Ok を返す fs::create_dir_all を使い、失敗の種類は io::Error の kind() で見分ける。
環境変数を読むには
std::env::var は環境変数が無い場合や不正な UTF-8 の場合に Err を返す Result 型である。未設定でも落とさないよう unwrap_or_else などで既定値を用意するが、空文字で設定されているときは Ok("") になって既定値は使われないので、空を未設定扱いにしたいなら取得後に自分で判定する。
配列をソートするには
Vec::sort は要素をその場で昇順に並べ替える破壊的メソッドである。降順や独自基準にするときは sort_by に比較クロージャを渡す。元の順序を残したいなら clone してから並べ替える。
数値をゼロ埋めするには
書式指定 {:05} は、幅 5 に足りない分を符号の後ろのゼロで埋める。幅を変数で決めるときは {:0width$} と書き、名前付き引数で幅を渡す。{:0>5} は「0 で右寄せ」という文字列の書式なので、数値を文字列にしてから使うと符号の前にゼロが入る。
数値を指定した範囲に収めるには
整数には Ord::clamp、浮動小数点数には f64::clamp があり、下限が上限より大きいと panic する。-5.clamp(0, 100) はメソッド呼び出しが単項の - より先に結び付いて -(5.clamp(0, 100)) と解釈され -5 になるので、負の数は括弧で囲む。
文字列を置換するには
str::replace はすべての一致箇所を置き換えた新しい String を返し、回数を制限したいときは replacen に上限回数を渡す。どちらも元の文字列は変更しない。探す対象には &str のほか char も渡せる。
数値を3桁区切りにするには
標準ライブラリの書式指定には 3 桁区切りが無いので、数字の列を先頭から見て、残りの桁数が 3 の倍数になる位置にカンマを入れる。符号は unsigned_abs で外してから最後に付け直す。abs を使わないのは、i64::MIN の絶対値が i64 に収まらず、abs ではオーバーフローでパニックするためである。
整数の割り算で商と余りを求めるには
/ と % は商を 0 の側へ切り捨て、余りは割られる数と同じ符号になる。割る数が正のとき、div_euclid と rem_euclid は商を小さい側へ切り下げ、0 以上の余りを返す。0 で割るとパニックするので、入力由来の割る数には Option を返す checked_div と checked_rem を使う。-17_i32.div_euclid(5) と書くとメソッド呼び出しが先に結び付いて -3 になるため、負のリテラルは括弧で囲むか変数に入れる。
小数を指定桁で丸めるには
f64::round は 0 から遠い側へ、round_ties_even は偶数の側へ整数に丸める。桁数を指定するメソッドは無いので、100 倍して丸めてから割り戻す。format! や println! の {:.2} は丸めた文字列を作るが、1.005 は内部の値が 1.00499… なので 1.00 になる。{:.0} で 2.5 を書式化すると 2 になり、round とは寄せる側が違う点にも注意する。
環境変数を真偽値として読むには
str の parse::<bool> が受け付けるのは小文字の "true" と "false" だけで、True や 1 は Err になる。環境変数では表記が揺れるため、to_ascii_lowercase で正規化してから match で受け付ける値を列挙し、未設定(VarError::NotPresent)と不正な値を区別して扱う。
パスからファイル名を取り出すには
file_name は最後の要素を Option<&OsStr> で返し、ルートや .. で終わるパスでは None になる。拡張子を除いた名前は file_stem で得られる。OsStr は OS のファイル名そのものなので、文字列として使う前に to_str で &str に変換し、UTF-8 でない名前で None になる場合に備えて unwrap_or などで既定値を決めておく。
ファイルに書き込むには
fs::write はファイルを作成または切り詰めてから内容を書き込む。追記は OpenOptions で append(true) を指定して開き、ファイルが無いときに作らせるなら create(true) も付ける。? 演算子で Result のエラーを伝播するため、main の戻り値を std::io::Result<()> にしておく。
HTTPでファイルをダウンロードするには
標準ライブラリに HTTP クライアントが無いため、reqwest の blocking 機能を使う。error_for_status() で 4xx / 5xx を Err に変えてから copy_to で本文を少しずつファイルへ書き出すので、エラーページを保存することも、本文全体をメモリに載せることもない。リダイレクトは既定で追う。
正規表現で大文字小文字を区別せずに一致させるには
regex クレートはパターン内の (?i) と RegexBuilder の case_insensitive(true) の両方に対応しており、どちらでも同じ結果になる。パターンを設定ファイルなどから受け取る場合はビルダー側で指定すると、利用者が書いたパターンを書き換えずに済む。
未実行
配列の最大値と最小値を求めるには
イテレータの max と min は Option を返し、空なら None になるので、空の場合の扱いを型で強制される。iter() ではなく into_iter() で呼ぶと Vec の所有権が移り、そのあとで元の変数を使うとコンパイルエラーになる。f64 は Ord を実装していないため max() が使えず、fold に f64::max を渡して比べる。
親ディレクトリのパスを取得するには
parent は最後の要素を取り除いたパスを Option<&Path> で返し、ルートでは None になる。report.csv のようにディレクトリ部分が無いときは None ではなく空のパスが返るので、カレントディレクトリとして使うなら空かどうかを確かめて . に置き換える。2 階層以上さかのぼるときは、自分自身から順に親をたどる ancestors を使う。
相対パスを絶対パスにするには
fs::canonicalize は .. の除去とシンボリックリンクの解決まで行う代わりに、パスが実在しないとエラーを返す。これから作るファイルの保存先を組み立てる段階では、Rust 1.79 で安定化した std::path::absolute を使う(POSIX では .. を残す)。
ファイルの拡張子を取り出すには
extension はドットを含まない拡張子を Option<&OsStr> で返し、拡張子が無い名前や .bashrc のようにドットで始まるだけの名前では None になる。OsStr は OS のファイル名そのものなので、文字列として比べる前に to_str で &str に変換する。
パスを連結するには
Path::join は新しい PathBuf を返し、PathBuf::push は自分自身を書き換える。どちらも追加する側が絶対パスだと、それまでのパスを丸ごと置き換える。Path は Display を実装していないので、表示するときは display() を通す。
日付に日数を足すには
標準ライブラリには暦の日付型が無いため chrono を使う。NaiveDate の checked_add_days と checked_sub_days は結果が範囲外になると None を返すので Option で受け取る。checked_add_months は存在しない日付を月末に丸めるため、1 月 31 日の 1 か月後は 2 月 28 日になる。
ファイルをコピーするには
fs::copy はパーミッションも複製したうえでコピーしたバイト数を返すが、宛先の存在は確かめないので上書きを避けたい場面には向かない。既存を守るなら create_new(true) で開き、AlreadyExists だけを他のエラーと分けて扱う。
文字列を数値に変換するには
parse は変換先の型を型注釈かターボフィッシュで指定し、結果を Result で返す。失敗が型に現れるので、unwrap で落とすか unwrap_or で既定値にするか match で分岐するかを、その場で選ぶことになる。16 進数などは from_str_radix を使う。
2つのJSONをマージするには
serde_json::Value のまま再帰し、両方がオブジェクトのときだけキー単位で降りていく。entry(...).or_insert(Value::Null) を挟むと、patch にしか無いキーも同じ経路で書き込める。serde_json クレートを Cargo.toml に足しておく。
未実行
環境変数の一覧を取得するには
env::vars は値が UTF-8 でないと panic するので、素性の分からない環境を走査するときは OsString を返す vars_os を使う。ソートやフィルタは Vec に集めてから通常のイテレータ操作で行う。
未実行
正規表現に一致する部分をすべて取り出すには
captures_iter は一致ごとに Captures を返し、find_iter は一致全体だけを返す。どちらも遅延評価のイテレータなので、必要な分だけ回すか collect でまとめて受け取るかを選べる。regex クレートを Cargo.toml に足しておく。
未実行
HTTPリクエストにタイムアウトを設定するには
ClientBuilder の connect_timeout は接続が確立するまで、timeout は応答を受け取り終えるまでの上限である。返ってきたエラーが時間切れかどうかは is_timeout で判定でき、接続拒否などと分けて扱える。
未実行
正規表現で部分文字列を取り出すには
captures は Option<Captures> を返すので、if let で取り出してから添字を引く。番号での添字と名前での添字のどちらも使えるが、存在しない添字はパニックになるため、パターンとコードを同時に直す。値が無いかもしれないグループは get を使って Option で受ける。
未実行
文字列が正規表現に一致するか調べるには
regex クレートを Cargo.toml の依存に追加してから使う。Regex::new は Result を返すため、リテラルのパターンなら unwrap でよいが、外部入力から作る場合は失敗を扱う。同じパターンを繰り返し使うときは、ループの外で 1 度だけ生成する。
未実行
正規表現で置換するには
replace_all が全件、replace が最初の 1 件で、どちらも Cow<str> を返すため元の文字列は変わらない。置換文字列の中では $1 や $name で後方参照できる。存在しない番号や名前を書いた場合は、エラーにならず空文字に置き換わる。
未実行