2022/09/24
はじめに
Rust の勉強を目的とし,Matrix クラスを作る.
それを通して得た知見を残す.
コード全体はこちら.
入門コース目次
- 入門 0 概要
- 入門 1 Struct とメソッド
- 入門 2 Unit Test
- 入門 3 演算子オーバーロードによるインデックスアクセス
- 入門 4 インスタンス生成用の自作マクロ
- 入門 5 module
- 入門 6 自作 Module を利用する
このページで作るもの
自分で作ったクラスに対するインスタンス生成用マクロを実装.
Rust におけるマクロ
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 におけるマクロは非常に強力なので,うまく使いこなしたいところですね!