Rustで環境変数を取得する
Rustで環境変数を取得する
std::env::var()
で。
成果物
参考
前回からの続き
大文字小文字を区別しない
まずは失敗するテストから書く。
#[cfg(test)] mod test { use super::*; #[test] fn case_sensitive() { let query = "duct"; // Rust // 安全かつ高速で生産的 // 三つを選んで // ガムテープ let contents = "\ Rust: safe, fast, productive. Pick three. Duct tape."; assert_eq!( vec!["safe, fast, productive."], search(query, contents) ); } #[test] fn case_insensitive() { let query = "rUsT"; // (最後の行のみ) // 私を信じて let contents = "\ Rust: safe, fast, productive. Pick three. Trust me."; assert_eq!( vec!["Rust:", "Trust me."], search_case_insensitive(query, contents) ); } }
実装。
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let query = query.to_lowercase(); let mut results = Vec::new(); for line in contents.lines() { if line.to_lowercase().contains(&query) { results.push(line); } } results }
str.to_lowercase()
がポイント。
区別する/しない
pub struct Config { pub query: String, pub filename: String, pub case_sensitive: bool, } impl Config { pub fn new(args: &[String]) -> Result<Config, &'static str> { if args.len() < 3 { return Err("引数不足。2つ必要です。第一引数に検索文字列、第二引数に検索対象ファイルパス。"); } let query = args[1].clone(); let filename = args[2].clone(); let case_sensitive = std::end::var("CASE_SENSITIVE").is_err(); // 環境変数の取得 Ok(Config { query, filename, case_sensitive }) } } pub fn run(config: Config) -> Result<(), Box<Error>> { let mut f = File::open(config.filename)?; let mut contents = String::new(); f.read_to_string(&mut contents)?; let result = if config.case_sensitive { search(&config.query, &contents); } else { search_case_insensitive(&config.query, &contents); }; for line in result { println!("{}", line); } Ok(()) }
std::env::var()
指定した環境変数があればResult
のOk
を返す。なければErr
。
Result.is_err()
Err
ならtrue
, Ok
ならfalse
。
実行
to
を含む。(大文字小文字を区別する)
$ cargo run to poem.txt ... query: to filename: poem.txt Are you nobody, too? How dreary to be somebody!
to
を含む。(大文字小文字を区別しない)
$ CASE_SENSITIVE=1 cargo run to poem.txt ... query: to filename: poem.txt Are you nobody, too? How dreary to be somebody! To tell your name the livelong day To an admiring bog!
To
も出てきた。成功。
ところでドキュメントは$ CASE_INSENSITIVE=1 cargo run to poem.txt
という間違った名前の環境変数で指定しているので期待通りにならない。誤字と思われる。
というか、文言の意味とコード間で整合性がとれていない。sensitive
は敏感の意。insensitive
はその対義語で鈍感の意。たぶんsensitive
だと大文字小文字の区別して、insensitive
だと区別しないのが正しい挙動と思われる。つまり以下のようにするのが正しいのでは?
pub struct Config { pub case_sensitive: bool, } impl Config { pub fn new(args: &[String]) -> Result<Config, &'static str> { let case_sensitive = std::end::var("CASE_SENSITIVE").is_ok(); // is_errでなく } } pub fn run(config: Config) -> Result<(), Box<Error>> { let result = if config.case_sensitive { search(&config.query, &contents); } else { search_case_insensitive(&config.query, &contents); }; }
実行結果は以下。
$ cargo run to poem.txt Finished dev [unoptimized + debuginfo] target(s) in 0.11s Running `/tmp/work/Rust.Minigrep.Env.20190701132148/src/2/minigrep/target/debug/minigrep to poem.txt` query: to filename: poem.txt Are you nobody, too? How dreary to be somebody! To tell your name the livelong day To an admiring bog!
CASE_SENSITIVE
環境変数を指定すると以下。(大文字小文字を区別する)
$ CASE_SENSITIVE=1 cargo run to poem.txt Compiling minigrep v0.1.0 (/tmp/work/Rust.Minigrep.Env.20190701132148/src/2/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 4.84s Running `/tmp/work/Rust.Minigrep.Env.20190701132148/src/2/minigrep/target/debug/minigrep to poem.txt` query: to filename: poem.txt Are you nobody, too? How dreary to be somebody!
環境変数を指定しないと大文字小文字を区別せずに出力する。たぶんこのほうがいい。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12(1)-release
- rustc 1.34.2 (6c2484dc3 2019-05-13)
- cargo 1.34.0 (6789d8a0a 2019-04-01)
$ uname -a Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux
前回まで
- Rustを学んでみたい(プログラミング言語)
- Rustの環境構築
- RustでHelloWorld
- Rustの和訳ドキュメント
- Cargoでプロジェクト作成・ビルド・実行
- クレートとは?
- Rustで関数を使ってみる
- Rustでモジュールを使ってみる
- Rustで乱数を生成する(rand)
- Rustで標準入力する(std::io::stdin().read_line())
- RustでMatch判定する(match)
- Rustでprintとread_lineを1行にする方法
- Rustで数当てゲーム
- クレート名にドット.が使えない
- Rustの変数と可変性(let, mut) error[E0384]: cannot assign twice to immutable variable
x
- Rustのimmutable束縛とconst定数の違い
- RustのREPL、evcxrのインストールに失敗した
- Rustでコンパイルするときの変数未使用warningを消す
- Rustの変数(再代入、再宣言(シャドーイング))
- Rustのシャドーイングについて
- イミュータブルについて(副作用)
- Rustの定数(const)
- Rustのデータ型(数値)
- Rustのデータ型(論理)
- Rustのデータ型(文字)
- Rustのデータ型(タプル)
- Rustのデータ型(配列)
- Rustの関数
- Rustのif式
- Rustのくりかえし文(loop)
- Rustのくりかえし文(while)
- Rustのくりかえし文(for)
- Rustの所有権(ムーブ)
- Rustの所有権(関数)
- Rustの所有権(スライス)
- Rustの構造体(定義とインスタンス化)
- Rustの構造体(プログラム例)
- Rustの構造体(メソッド)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustのmatch(制御フロー演算子)
- RustでNULLを扱う(Option, Some, None)
- NULL参照は10億ドルの失敗だった
- Rustの列挙型に独自表示を実装する(E0277 対策 std::fmt::Display 実装)
- RustのIfLet(matchの糖衣構文)
- Rustのプロジェクト構造
- Rustのcargoでライブラリ&テスト(単体、結合)
- Rustのモジュール(mod)
- Rustのモジュール(pub)
- Rustのmod参照方法(
mod 子モジュール名;
,use 要素名;
,extern crate クレート名;
,super
) - Rustのインポートまとめ(Rust2018)
- RustのコレクションVec型
- RustのコレクションString型
- RustのコレクションHashMap型
- Rustのコレクション(練習問題)
- Rustのエラー処理
- Rustのジェネリクス
- Rustのトレイト
- Rustのライフタイム1
- Rustのライフタイム2(構造体の定義)
- Rustのライフタイム3(ライフタイム省略)
- Rustのライフタイム4(impl定義)
- Rustの静的ライフタイム5('static)
- Rustのライフタイム6(ジェネリクス、トレイト境界とともに)
- Rustのテストコードを書く
- Rustのテスト実行
- Rustのテスト体系化
- Rustでコマンドライン引数を受け取る
- Rustのファイル読込
- Rustでリファクタリング(モジュール性とエラー処理の向上)
- Rustでテスト駆動開発