元ネタ
やってみた
#[test]
fn run() {
assert_eq!("アーロン", "アローラロコン".chars().step_by(2).collect::<String>());
}
chars()
"アローラロコン"
を文字ごとに分けたイテレータへ変換する.
ちなみに Rust の char
は Unicode で定義された 1 コードポイントのことである.人間が通常認識する 1 文字は 1 書記素と表現されることが多いが,コードポイントはより小さい単位である.従って,多くの絵文字は複数の char
に変換される点に注意が必要.一方で,今回のケースではコードポイントと書記素の数が等しいので,これを使って問題ない.
Rust の char
について詳しくは以下で説明されている:
step_by(2)
イテレータの next()
を直接的または間接的に呼んだときにステップする数を変える.今回のケースでは 1 回 next()
を呼ぶごとに (一つおきに読ませるために) 2 要素ステップさせたいので, 2
を指定.
collect::<String>()
イテレータを全走査してある型の値に変換する.
ここで現在のイテレータを Iterator<Item = T>
とすれば, FromIterator<T>
を実装している型に変換できる.今回のケースでは, String
が for<'a> FromIterator<&'a char>
を実装しているので, Iterator<Item = &'_ char>
から変換できる.
なおこの式の代入される先によってどの型になればよいか明確なときは型推論が働くため collect
だけの記述でよい.今回は型推論が効かないケースだったので, ::<String>
で明示的に指定した.
&<expr>
地味に存在している先頭の &
は collect::<String>()
された結果に係っており,この参照である &String
として借用するかたちになる. assert_eq!
の左辺である "アーロン"
は &'static str
であって, String
ではないから,どちらかを寄せる必要がある. String::from("アーロン")
とする,逆に <略>.collect::<String>().as_ref()
とすることもできる.一方で &
を用いるのが一番短く済むため,こちらを採用した.
追記: for<'a> &'a str
は PartialEq<String>
を実装しているため,これがなくても動作した.