私は4つの文字識別子の巨大なリストを持っています。私はそれぞれの列挙定数が必要です。定数の値はASCII識別子でu32
とする必要があります。マクロを使ってCスタイルの `enum`値を計算することはできますか?
enum E {
Elem = my_macro!(Elem),
}
マクロは単に結果のASTで置き換えられるため、コンパイラは定数ではない式を参照してエラーを発生させます。
これが可能ですか、または明示的に定数を書き出す必要がありますか?
私は4つの文字識別子の巨大なリストを持っています。私はそれぞれの列挙定数が必要です。定数の値はASCII識別子でu32
とする必要があります。マクロを使ってCスタイルの `enum`値を計算することはできますか?
enum E {
Elem = my_macro!(Elem),
}
マクロは単に結果のASTで置き換えられるため、コンパイラは定数ではない式を参照してエラーを発生させます。
これが可能ですか、または明示的に定数を書き出す必要がありますか?
種類はありますが、実際にはマクロでは本当に新しい機能を追加するのではなく、慎重に削除することができます。
まず、マクロを使用しないでコードを作成します。これにより、可能なことが表示されます。例えば、私の探検は次のように行ってきました:
#[repr(u32)]
enum Foo {
Start = (1 << 24 | 2 << 16 | 3 << 8 | 4) as u32,
Start2 = ((b'1' as u32) << 24 | 2 << 16 | 3 << 8 | 4) as u32,
// the index operation on const values is unstable
//Start3 = ((b"1"[0] as u32) << 24 | 2 << 16 | 3 << 8 | 4) as u32,
}
悲しいことに、我々は定数式は(まだ)ない定数にインデックスとして最後のフォームを使用することはできません。私が知る限り、できることはStart2
です。次に、冗長性が発生した場所を確認するためにパターンを数回繰り返します。今、あなたがマクロを作成するためにプライミングされている
#[repr(u32)]
enum Foo {
Start = ((b'S' as u32) << 24 | (b'T' as u32) << 16 | (b'R' as u32) << 8 | (b'T' as u32)) as u32,
End = ((b' ' as u32) << 24 | (b'E' as u32) << 16 | (b'N' as u32) << 8 | (b'D' as u32)) as u32,
}
:
macro_rules! tagged_ascii_headers {
(enum $name:ident {
$($var:ident = $v1:expr, $v2:expr, $v3:expr, $v4:expr,)*
}) => {
#[repr(u32)]
enum $name {
$($var = (($v1 as u32) << 24 | ($v2 as u32) << 16 | ($v3 as u32) << 8 | $v4 as u32),)*
}
}
}
tagged_ascii_headers! {
enum Foo {
Start = b'S', b'T', b'R', b'T',
End = b' ', b'E', b'N', b'D',
}
}
を次に、あなたはその何かを見つけるために、マクロの構文で遊ぶことができますいい感じ。私はダウンしました
macro_rules! tagged_ascii_headers {
(enum $name:ident {
$($var:ident = $v1:tt $v2:tt $v3:tt $v4:tt,)*
}) => {
#[repr(u32)]
enum $name {
$($var = (($v1 as u32) << 24 | ($v2 as u32) << 16 | ($v3 as u32) << 8 | $v4 as u32),)*
}
}
}
tagged_ascii_headers! {
enum Foo {
Start = 'S' 'T' 'R' 'T',
End = ' ' 'E' 'N' 'D',
}
}
これはちょっといいですが、最終的にはもっと一定の評価が必要な場合があります。 配列のインデックスを作成することができれば、マクロが単に結果ASTに置き換えられますので、あなたが
tagged_ascii_headers! {
enum Foo {
Start = b"STRT",
End = b" END",
}
}
のようなものに進化する可能性が
これは本当です
コンパイラには定数式がありません
これは半分です。たとえば、これはうまくコンパイル:本当に、マクロがconstのネスとは無関係である
macro_rules! foo {
() => { 42 }
}
enum Foo {
Start = foo!(),
}
だから、それはマクロがに展開かについてすべてです。
また、ビルドスクリプトに移動することができます:
const THINGS: &'static [(&'static str, &'static [u8; 4])] = &[
("Start", b"STRT"),
("End", b" END"),
];
fn main() {
println!("#[repr(u32)]");
println!("enum Foo {{");
for &(name, code) in THINGS {
let code = (code[0] as u32) << 24 |
(code[1] as u32) << 16 |
(code[2] as u32) << 8 |
code[3] as u32;
println!(" {} = {},", name, code);
}
println!("}}");
}
本番コードから生成されたファイルが含まれ、その後、代わりに標準出力のファイルにそれを書きたいと思います。ビルドスクリプトを使用すると、すべての名前/コードを定義する外部ファイルを作成することができます。
ビルドスクリプトは最もクリーンな解決策です。私は言語でこれを解決できることを望んでいましたが。 –
@BlankChisui *これを言語で解決する* - ビルドスクリプト**は**言語の一部です。あなたはまだ錆のコードを書いており、それは貨物のファーストクラスの側面です。たくさんのプロジェクトがビルドスクリプトを使用しています。 – Shepmaster
おそらく、1.1のマクロを考えたり、buildgenスクリプトを使って(スクリプトベースのテンプレートを使って)codegenを使っているとしますか? – user25064
@ user25064 Macros 1.1がどのように役立つと思いますか?以下の答えはすでにビルドスクリプトを記述しています。 – Shepmaster
あなたは文字列としてenum要素を持っているので、マクロ1.1で文字を繰り返し処理できますか?包括的な答えをいただきありがとうございます。 – user25064