此代码:
#![feature(macro_rules)]
macro_rules! new(
($my_type:ty) => ( $my_type::new() );
)
struct Foo {
blah: int
}
impl Foo {
fn new() -> Foo {
return Foo { blah: 0 }
}
}
fn main() {
let my_foo = new!(Foo);
println!("Foo's value: {}", my_foo.blah);
}
看起来很好,但它失败并出现此错误:
test.rs:4:25: 4:32 error: unexpected token: `Foo`
test.rs:4 ($my_type:ty) => ( $my_type::new() );
^~~~~~~
如果我进入宏并将$my_type
替换为Foo
,它会编译并运行得很好,因此Foo
在该位置显然有效。除非Foo
显然来自宏观替换。
如果我运行rustc test.rs --pretty expanded
,它就不会显示扩展的宏。它只是给了我相同的错误信息。我怀疑这意味着它在扩展宏之前生成了消息,但它可能只是除非编译成功,否则它不会显示任何内容。虽然这会严重限制--pretty expanded
的有用性。
基于其他实验,我可以在基本上每个其他地方使用宏类型参数。你不能在它们上面调用静态函数。这似乎是一个相当随意的限制,错误信息肯定没有帮助。
为什么存在这种限制?它有办法吗?
答案 0 :(得分:6)
Foo::bar()
语法正在创建路径Foo::bar
然后调用该函数,并且仅适用于有效路径,它不适用于任意类型,例如(u8, i8)::bar()
不起作用。您可以使用ident
宏非终端,该终端采用单个标识符,并且可以在标识符有效的情况下使用,包括在路径中
#![feature(macro_rules)]
macro_rules! new(
($my_type: ident) => ( $my_type::new() );
)
struct Foo {
blah: int
}
impl Foo {
fn new() -> Foo {
return Foo { blah: 0 }
}
}
fn main() {
let my_foo = new!(Foo);
println!("Foo's value: {}", my_foo.blah);
}
UFCS提供了通过语法<Type>::new()
在任意类型上调用此类方法,因此,在实现时,用
macro_rules! new(
($my_type: ty) => ( <$my_type>::new() );
)
也应该有用。