はじめに
こんにちは。細々とプログラミングをしているsotanengelです。
この記事は以下の記事の連載です。
他の連載記事 (詳細)
- Day 1:型システムを使ってデータ構造を再現しよう
- Day 2:型システムを用いて共通の挙動を表現しよう
- Day 3:OptionとResultに対してはmatchを用いずに変換しよう
- Day 4:標準のErrorを使おう
- Day 5:型変換を理解しよう
- Day 6:newtypeパターンを活用しよう
- Day 7:複雑な型にはビルダを使おう
- Day 8:明示的なループの代わりにイテレータ変換を使用することを検討しよう
- Day 9:標準トレイトに習熟しよう
- Day 10:RIIパターンにはDropトレイトを実装しよう
- Day 11:ジェネリクスとトレイトオブジェクトのトレードオフを理解しよう
- Day 12:デフォルト実装を用いて、実装しなければならないトレイトメソッドを最小限にしよう
- Day 13:Don't panic
- Day 14:リフレクションを避けよう
- Day 15:可視範囲を最小化しよう
また本記事はEffective Rust(David Drysdale (著), 中田 秀基 (翻訳))を参考に作成されております。とてもいい書籍ですので興味を持った方は、ぜひ読んでみてください!
今日の内容
概要
Rustではイテレータを使うことで愚直にループを書くよりも効率的になる場合があります。
そこでイテレータを使って何ができるか試してみましょう。
イテレータで配列の合計値を算出しましょう
問(リンク)
以下のコードでは愚直に書いているので、iter
とsum
を使ってコードを書き直してみましょう。
コード (詳細)
#[allow(clippy::useless_vec)]
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// TODO: イテレータを使って簡潔に実装し直してください。
let mut sum = 0;
for i in 0..numbers.len() {
sum += numbers[i];
}
println!("Sum: {}", sum);
}
解答(リンク)
コード参照。
コード (詳細)
#[allow(clippy::useless_vec)]
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// イテレータを使って合計を計算します。
let sum: i32 = numbers.iter().sum();
println!("Sum: {}", sum);
}
配列のnの倍数の場所にある要素を取得しましょう
問(リンク)
配列の3番目の要素だけを合計する機能をskip
やstep_by
を使って実装してください。
コード (詳細)
#[allow(clippy::useless_vec)]
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let mut sum = 0;
let mut index = 2; // 最初の2要素をスキップ
// TODO: イテレータを使って簡潔に実装し直してください。
while index < numbers.len() {
sum += numbers[index];
index += 3; // 3つおきに要素を取得
}
println!("Sum of elements at multiples of 3 indices: {}", sum);
}
解答(リンク)
コード参照。
コード (詳細)
#[allow(clippy::useless_vec)]
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let sum: i32 = numbers
.iter()
.skip(2) // 最初の2要素をスキップ
.step_by(3) // 3つおきに要素を取得
.sum();
println!("Sum of elements at multiples of 3 indices: {}", sum);
}
特定の条件の要素だけ抽出しましょう
問(リンク)
奇数かつ、10未満の要素を抽出するためにfilter
やcollect
を使って実装してください。
コード (詳細)
#[allow(clippy::useless_vec)]
fn main() {
let numbers = vec![17, 3, 25, 8, 42, 7, 19, 6, 1, 12, 9, 5];
let mut odd_numbers = Vec::new();
// TODO: イテレータを使って簡潔に実装し直してください。
for i in 0..numbers.len() {
let x = numbers[i];
if x % 2 != 0 && x < 10 {
odd_numbers.push(x);
}
}
println!("{:?}", odd_numbers);
}
解答(リンク)
コード参照。
コード (詳細)
#[allow(clippy::useless_vec)]
fn main() {
let numbers = vec![17, 3, 25, 8, 42, 7, 19, 6, 1, 12, 9, 5];
let odd_numbers: Vec<i32> = numbers
.iter()
.filter(|&&x| x % 2 != 0 && x < 10)
.copied()
.collect();
println!("{:?}", odd_numbers);
}
ターボフィッシュ記法を使いこなそう。
問(リンク)
collect
とターボフィッシュ記法を使うことで、失敗する可能性のある処理をResult型に格納して返却する実装をしてください。
コード (詳細)
fn parse_numbers(items: Vec<&str>) -> Result<Vec<i32>, std::num::ParseIntError> {
let mut results = Vec::new();
// TODO: イテレータを使って簡潔に実装し直してください。
for i in 0..items.len() {
match items[i].parse::<i32>() {
Ok(num) => results.push(num),
Err(e) => return Err(e),
}
}
Ok(results)
}
#[allow(clippy::useless_vec)]
fn main() {
let items = vec!["42", "93", "apple", "17"];
let parsed = parse_numbers(items);
match parsed {
Ok(numbers) => println!("Parsed numbers: {:?}", numbers),
Err(e) => eprintln!("Failed to parse: {}", e),
}
}
解答(リンク)
コード参照。
コード (詳細)
fn parse_numbers(items: Vec<&str>) -> Result<Vec<i32>, std::num::ParseIntError> {
items
.into_iter()
.map(|item| item.parse::<i32>())
.collect::<Result<Vec<_>, _>>()
}
#[allow(clippy::useless_vec)]
fn main() {
let items = vec!["42", "93", "apple", "17"];
let parsed = parse_numbers(items);
match parsed {
Ok(numbers) => println!("Parsed numbers: {:?}", numbers),
Err(e) => eprintln!("Failed to parse: {}", e),
}
}
さいごに
もしも本リポジトリで不備などあれば、リポジトリのissueやPRなどでご指摘いただければと思います。