ys memos

Blog

Rust入門 Matrixクラス 4 インスタンス生成用マクロ


rust

2022/09/24


Rust の勉強を目的とし,Matrix クラスを作る.

それを通して得た知見を残す.

コード全体はこちら



自分で作ったクラスに対するインスタンス生成用マクロを実装.


Rust におけるマクロは言語拡張のようなもので,C++の#defineマクロよりも言語と統合されており,エラーの原因になりづらいとのこと.

また,マクロ呼び出し時には!を付ける必要があり,呼び出し側で明らかにマクロを呼び出していることを理解できるようになっている.

代表的なマクロには,println!assert!などがある.

また,マクロは宣言的(declarative)マクロと手続き的(procedural)マクロに大別されるとのこと.

ここでは,宣言的マクロのみ扱う.


src/matrix/macros.rs
#[macro_export]
macro_rules! matrix {
    [$($elements:expr), *] => {
        {
            let mut vec_2d = vec![];
            $(
              vec_2d.push($elements.to_vec());
            )*
            $crate::matrix::Matrix::new(vec_2d)
        }
    };
}

#[cfg(test)]
mod tests {
    use crate::matrix::Matrix;

    #[test]
    fn can_create_matrix_1x1() {
        let mat = matrix![[1]];
        assert_eq!(mat, Matrix::new(vec![vec![1]]));
    }

    #[test]
    fn can_create_matrix_1x2() {
        let mat = matrix![[1], [2]];
        assert_eq!(mat, Matrix::new(vec![vec![1], vec![2]]));
    }

    #[test]
    fn can_create_matrix_2x2() {
        let mat = matrix![[1, 3], [2, 4]];
        assert_eq!(mat, Matrix::new(vec![vec![1, 3], vec![2, 4]]));
    }

    #[test]
    fn can_create_matrix_3x3() {
        let mat = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]];
        assert_eq!(
            mat,
            Matrix::new(vec![vec![0, 1, 2], vec![3, 4, 5], vec![6, 7, 8]])
        );
    }
}


macro_rules!によってマクロを定義することが出来る.

#[macro_export]はマクロに対するpubのようなもので,これにより,外部からマクロを利用することが出来る.

#[macro_export]
macro_rules! matrix {
    [$($elements:expr), *] => {
        {
            let mut vec_2d = vec![];
            $(
              vec_2d.push($elements.to_vec());
            )*
            $crate::matrix::Matrix::new(vec_2d)
        }
    };
}

matrix!マクロが正常に動作することを確認する.

ここでは,matrix![[]]でインスタンス生成を行うが,マクロの特性上,matrix!([])/ matrix!{[]}でもマクロ呼び出しが可能であるという点は留意する必要がある.

#[cfg(test)]
mod tests {
    use crate::matrix::Matrix;

    #[test]
    fn can_create_matrix_1x1() {
        let mat = matrix![[1]];
        assert_eq!(mat, Matrix::new(vec![vec![1]]));
    }

    #[test]
    fn can_create_matrix_1x2() {
        let mat = matrix![[1], [2]];
        assert_eq!(mat, Matrix::new(vec![vec![1], vec![2]]));
    }

    #[test]
    fn can_create_matrix_2x2() {
        let mat = matrix![[1, 3], [2, 4]];
        assert_eq!(mat, Matrix::new(vec![vec![1, 3], vec![2, 4]]));
    }

    #[test]
    fn can_create_matrix_3x3() {
        let mat = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]];
        assert_eq!(
            mat,
            Matrix::new(vec![vec![0, 1, 2], vec![3, 4, 5], vec![6, 7, 8]])
        );
    }
}

Rust におけるマクロは非常に強力なので,うまく使いこなしたいところですね!


関連タグを探す