一つの方法は次のとおりです。
macro_rules! unique_args {
($($idents:ident),*) => {
{
#[allow(dead_code, non_camel_case_types)]
enum Idents { $($idents,)* __CountIdentsLast }
}
};
}
macro_rules! _my_elem {
($val:expr, $($var:expr),*) => {{
$($val == $var)||*
}};
}
macro_rules! my_elem {
($($tt:tt)*) => {{
unique_args!($($tt)*);
_my_elem!($($tt)*)
}};
}
アイデアは、列挙型が重複バリアント名を持つことができないので、二度同じ識別子を持つことがコンパイラエラーを引き起こすということです。
あなたのようなこれを使用することができます:ここでは
if my_elem!(w, x, y, z) {
println!("{}", w);
}
がエラーと例です
// error[E0428]: a value named `y` has already been defined in this enum
if my_elem!(w, x, y, y) {
println!("{}", w);
}
しかし、これが唯一の識別子で動作します。
あなたにもリテラルを使用する場合は、リテラルと識別子を区別できるように異なる構文を持つマクロが必要になります。
macro_rules! unique_idents {
() => {
};
($tt:tt) => {
};
($ident1:ident, $ident2:ident) => {
{
#[allow(dead_code, non_camel_case_types)]
enum Idents {
$ident1,
$ident2,
}
}
};
($ident:ident, lit $expr:expr) => {
};
($ident1:ident, $ident2:ident, $($tt:tt)*) => {
{
#[allow(dead_code, non_camel_case_types)]
enum Idents {
$ident1,
$ident2,
}
unique_idents!($ident1, $($tt)*);
unique_idents!($ident2, $($tt)*);
}
};
($ident:ident, lit $expr:expr, $($tt:tt)*) => {
unique_idents!($ident, $($tt)*);
};
(lit $expr:expr, $($tt:tt)*) => {
unique_idents!($($tt)*);
};
}
macro_rules! unique_literals {
() => {
};
($tt:tt) => {
};
(lit $lit1:expr, lit $lit2:expr) => {{
type ArrayForStaticAssert_ = [i8; 0 - (($lit1 == $lit2) as usize)];
}};
(lit $lit:expr, $ident:ident) => {
};
(lit $lit1:expr, lit $lit2:ident, $($tt:tt)*) => {{
unique_literals!(lit $lit1, lit $lit2);
unique_literals!(lit $lit1, $($tt)*);
unique_literals!(lit $lit2, $($tt)*);
}};
(lit $lit:expr, $ident:ident, $($tt:tt)*) => {
unique_literals!(lit $lit, $($tt)*);
};
($ident:ident, $($tt:tt)*) => {
unique_literals!($($tt)*);
};
}
macro_rules! unique_args2 {
($($tt:tt)*) => {{
unique_idents!($($tt)*);
unique_literals!($($tt)*);
}};
}
macro_rules! _elem {
() => {
false
};
($val:expr) => {
false
};
($val1:expr, $val2:expr) => {{
$val1 == $val2
}};
($val1:expr, lit $val2:expr) => {{
$val1 == $val2
}};
($val1:expr, $val2:expr, $($tt:tt)*) => {{
$val1 == $val2 || _elem!($val1, $($tt)*)
}};
($val1:expr, lit $val2:expr, $($tt:tt)*) => {{
$val1 == $val2 || _elem!($val1, $($tt)*)
}};
}
macro_rules! elem {
($($tt:tt)*) => {{
unique_args2!($($tt)*);
_elem!($($tt)*)
}};
}
uniq_idents!
マクロは、上記と同じトリックを使用しています。
unique_literals!
マクロは、コンパイル時にキャッチされるsubtract with overflow
エラーを発生させます。
これらのマクロを使用すると、3210で各リテラルの前に付ける必要がありますが:ここでは
if elem!(w, x, lit 1, z) {
println!("{}", w);
}
は、エラーのいくつかの例は次のとおりです。
// error[E0428]: a value named `y` has already been defined in this enum
if elem!(w, x, y, y) {
println!("{}", w);
}
// error[E0080]: constant evaluation error
if elem!(w, x, lit 1, z, lit 1) {
println!("{}", w);
}
私はそれは我々が使用しなくてもできる最善だと思いますコンパイラプラグイン。
これらのマクロを改善することは可能ですが、あなたはそのアイデアを得るでしょう。
式を文字列に変換するために使用できるstringify!
マクロがあるにもかかわらず、コンパイル時にこれらの文字列を比較する方法はまだありません(少なくともコンパイラプラグインなし)。我々はconst fn
を持っています。
私の答えがあなたが探しているものでない場合は、理由を説明するコメントを投稿できますか? – antoyo