LoginSignup
0
1

More than 5 years have passed since last update.

Rustでイテレート可能なタプル

Last updated at Posted at 2018-06-06

Rustでイテレート可能なタプルを作ってみた。
これを使えば可変個引数とか出来るかもしれない。


//型宣言用 (型1, (型2, (型3, ()))) こんなタプルになる
#[macro_export]
macro_rules! variadic_type {
    { $t:ty } => { ($t,()) };
    { $t:ty,$($u:ty),+ } => { ($t, variadic_type!($($u),+)) };
}

//インスタンス用 (値1, (値2, (値3, ()))) こんなタプルになる
#[macro_export]
macro_rules! variadic {
    { $e:expr } => { ($e,()) };
    { $e:expr,$($f:expr),+ } => { ($e, variadic!($($f),+)) };
}

//◯番目の値を取得
//力技にせざるを得なかった
#[macro_export]
macro_rules! variadic_get {
    { $e:expr,0 } => { &$e.0 };
    { $e:expr,1 } => { &($e.1).0 };
    { $e:expr,2 } => { &(($e.1).1).0 };
    { $e:expr,3 } => { &((($e.1).1).1).0 };
    { $e:expr,4 } => { &(((($e.1).1).1).1).0 };
//たくさん増やしておこう
}

//variadic_getのmutable版
#[macro_export]
macro_rules! variadic_get_mut {
    { $e:expr,0 } => { &mut $e.0 };
    { $e:expr,1 } => { &mut ($e.1).0 };
    { $e:expr,2 } => { &mut (($e.1).1).0 };
    { $e:expr,3 } => { &mut ((($e.1).1).1).0 };
    { $e:expr,4 } => { &mut (((($e.1).1).1).1).0 };
}

//各要素に対して、順次同じメソッドを呼ぶためのimplを定義する
#[macro_export]
macro_rules! variadic_impl {
    { $p:path,$i:ident } => { 
        impl $p for (()) {
            fn $i(&mut self) {
            }
        }
        impl<T,U> $p for (T,U) where T:$p, U:$p {
            fn $i(&mut self) {
                (self.0).$i();
                (self.1).$i();
            }
        }
    }
}

使い方はこんな感じ

pub trait Update {
    fn update(&mut self);
}

struct Test1 {

}
impl Update for Test1 {
    fn update(&mut self) {
        println!("test1");
    }
}
struct Test2 {

}
impl Update for Test2 {
    fn update(&mut self) {
        println!("test2");
    }
}
struct Test3 {
    i: i32,
}
impl Update for Test3 {
    fn update(&mut self) {
        println!("test3 {}", self.i);
    }
}

fn main() {

    //型宣言したいならこう(使わなくてもOK)
    type TTT = variadic_type!(Test1,Test2,Test3);

    //インスタンスつくる
    let mut v:TTT = variadic!(Test1{}, Test2{},Test3{i:1});

    //Update::updateが呼べるように準備
    variadic_impl!(Update,update);

    //呼ぶ!
    v.update();

    {
                //中身を変更してみる
        let a = variadic_get_mut!(v, 2);
        a.i = 10;
    }

    //呼ぶ!
    v.update();
}

実行結果

test1
test2
test3 1
test1
test2
test3 10

こちらで試せます。
https://play.rust-lang.org/?gist=0e08f1648251d02a016d6d3d4e75185e&version=stable&mode=debug

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1