我正在尝试使用相同的初始化程序来初始化一大堆元素。 64 个元素只是一个例子——我想让它至少达到 16k。不幸的是一个简单的
let array : [AllocatedMemory<u8>; 64] = [AllocatedMemory::<u8>{mem:&mut []};64];
不会工作,因为 AllocatedMemory
结构没有实现 Copy
error: the trait `core::marker::Copy` is not implemented for the type `AllocatedMemory<'_, u8>` [E0277]
let array : [AllocatedMemory<u8>; 64] = [AllocatedMemory::<u8>{mem:&mut []}; 64];
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
所以我尝试了宏无济于事:
struct AllocatedMemory<'a, T: 'a> {
mem: &'a mut [T],
}
macro_rules! init_memory_helper {
(1, $T : ty) => { AllocatedMemory::<$T>{mem: &mut []} };
(2, $T : ty) => { init_memory_helper!(1, $T), init_memory_helper!(1, $T) };
(4, $T : ty) => { init_memory_helper!(2, $T), init_memory_helper!(2, $T) };
(8, $T : ty) => { init_memory_helper!(4, $T), init_memory_helper!(4, $T) };
(16, $T : ty) => { init_memory_helper!(8, $T), init_memory_helper!(8, $T) };
(32, $T : ty) => { init_memory_helper!(16, $T), init_memory_helper!(16, $T) };
(64, $T : ty) => { init_memory_helper!(32, $T), init_memory_helper!(32, $T) };
}
macro_rules! init_memory {
(1, $T : ty) => { [init_memory_helper!(1, $T)] };
(2, $T : ty) => { [init_memory_helper!(2, $T)] };
(4, $T : ty) => { [init_memory_helper!(4, $T)] };
(8, $T : ty) => { [init_memory_helper!(8, $T)] };
(16, $T : ty) => { [init_memory_helper!(16, $T)] };
(32, $T : ty) => { [init_memory_helper!(32, $T)] };
(64, $T : ty) => { [init_memory_helper!(64, $T)] };
}
fn main() {
let array: [AllocatedMemory<u8>; 64] = init_memory!(64, u8);
println!("{:?}", array[0].mem.len());
}
错误信息是
error: macro expansion ignores token `,` and any following
(64, $T : ty) => { init_memory_helper!(32, $T), init_memory_helper!(32, $T) };
note: caused by the macro expansion here; the usage of `init_memory_helper!` is likely invalid in expression context
有没有什么方法可以在不剪切和粘贴每个初始化程序的情况下初始化这个数组?
最佳答案
问题是 the expansion of a macro absolutely must be a complete and independently valid grammar element .您不能扩展到 a, b
,就像您不能扩展到 42 +
一样。在 Rust 中也没有办法(静态地)连接或 cons 数组;整个数组初始化器必须在一个步骤中扩展。
这可以使用带有 push-down accumulation 的宏来完成.诀窍是您将语法上尚未有效的部分数组表达式向下传递给递归,而不是在返回的途中进行构造。当您到达扩展的底部时,您会立即发出现在完整的表达式。
这是一个支持长度为 0 到 8 的数组以及 2 的幂到 64 的宏:
macro_rules! array {
(@accum (0, $($_es:expr),*) -> ($($body:tt)*))
=> {array!(@as_expr [$($body)*])};
(@accum (1, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (0, $($es),*) -> ($($body)* $($es,)*))};
(@accum (2, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (0, $($es),*) -> ($($body)* $($es,)* $($es,)*))};
(@accum (3, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (2, $($es),*) -> ($($body)* $($es,)*))};
(@accum (4, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (2, $($es,)* $($es),*) -> ($($body)*))};
(@accum (5, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (4, $($es),*) -> ($($body)* $($es,)*))};
(@accum (6, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)*))};
(@accum (7, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)* $($es,)*))};
(@accum (8, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (4, $($es,)* $($es),*) -> ($($body)*))};
(@accum (16, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (8, $($es,)* $($es),*) -> ($($body)*))};
(@accum (32, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (16, $($es,)* $($es),*) -> ($($body)*))};
(@accum (64, $($es:expr),*) -> ($($body:tt)*))
=> {array!(@accum (32, $($es,)* $($es),*) -> ($($body)*))};
(@as_expr $e:expr) => {$e};
[$e:expr; $n:tt] => { array!(@accum ($n, $e) -> ()) };
}
fn main() {
let ones: [i32; 64] = array![1; 64];
println!("{:?}", &ones[..]);
}
这里的策略是将输入的大小乘以 2 的幂,然后加上非 2 的幂的余数。这是为了通过确保 $n
快速下降值来避免宏递归限制(我相信默认值为 64)。
只是为了防止频繁的后续问题:不,你不能用算术来简化它;你不能在宏中做算术。 :)
附录:如果你不确定这是如何工作的,你可以在编译时将-Z trace-macros
传递给rustc
看看每个扩展的宏调用。使用 array![1; 6]
例如,您会得到如下内容:
array! { 1 ; 6 }
array! { @ accum ( 6 , 1 ) -> ( ) }
array! { @ accum ( 4 , 1 ) -> ( 1 , 1 , ) }
array! { @ accum ( 2 , 1 , 1 ) -> ( 1 , 1 , ) }
array! { @ accum ( 0 , 1 , 1 ) -> ( 1 , 1 , 1 , 1 , 1 , 1 , ) }
array! { @ as_expr [ 1 , 1 , 1 , 1 , 1 , 1 , ] }
关于rust - 使用宏初始化大量非复制元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36258417/