Rustでcar/cdr的なもの
Rustでcar/cdr
的なものは無いか?
fn main() {
let v = vec![1, 2, 3, 4, 5];
let (hd, tl) = v.split_first().unwrap();
assert_eq!(hd, &1);
assert_eq!(tl, &[2, 3, 4, 5]);
}
split_first
は、Option<(&T, &[T])>
を返します。これを利用すればcar/cdr関数と同じように処理できます。split_first_mut
というものもあり、こちらはミュータブルな参照を返します。car/cdrという名前で使いたい場合は以下のような関数を作成すればいいかと思います。
fn car(v: &[i32]) -> &i32 {
let (hd, _) = v.split_first().unwrap();
hd
}
fn cdr(v: &[i32]) -> &[i32] {
let (_, tl) = v.split_first().unwrap();
tl
}
または以下のような形も良いかもしれません。
fn car(v: &[i32]) -> &i32 {
match v.split_first() {
Some((hd, _)) => hd,
None => panic!("TYPE-ERROR")
}
}
fn cdr(v: &[i32]) -> &[i32] {
match v.split_first() {
Some((_, tl)) => tl,
None => panic!("TYPE-ERROR")
}
}
このsplit_first()
を用いて繰り返し処理もできます。
fn my_for(v: &[i32]) {
if let Some((hd, tl)) = v.split_first() {
println!("{}", hd);
my_for(tl);
};
}
fn main() {
let v = vec![1, 2, 3, 4, 5];
my_for(&v);
}
----
結果
----
1
2
3
4
5
上記のコードだと、split_first
がSomeの場合だけ処理されるので、Noneになった時点で、処理はストップします。Rustはちゃんとかゆいところに手が届くように設計されている。
さらに上記の
my_for
にひと手間加えると以下のようにごっそり中身を変えることも出来ます。
fn my_for(v: &mut [i32], f: fn(i32) -> i32) {
if let Some((hd, tl)) = v.split_first_mut() {
*hd = f(*hd);
my_for(tl, f);
};
}
fn main() {
let mut v = vec![1,2,3,4,5];
let f = |x| x + 10;
my_for(&mut v, f);
assert_eq!(v, vec![11,12,13,14,15]);
}
あまり良くないことではありますが……