如何让Rust声明式宏b!支持结构体字段文档悬停显示?
如何让声明式宏b!支持字段文档悬停?
我有两个用于构建同一Hello结构体的声明式宏:a!使用通用标识符匹配字段名,b!匹配特定的name字段。但在VS Code中,只有a!能在宏调用内的name上悬停显示字段的文档注释。请问如何让b!也实现该功能?
代码示例
struct Hello { /// Name docs name: String } macro_rules! a { ($name:ident: $value:expr) => { Hello { $name: $value } }; } macro_rules! b { (name: $expr:expr) => { Hello { name: $expr } }; } fn main() { let hello_alice = a!(name: String::from("Alice")); let hello_bob = b!(name: String::from("Bob")); }
问题原因
b!的匹配器里的name是硬编码的字面量,Rust语言服务(如Rust Analyzer)无法将其与Hello结构体的name字段建立关联。而a!使用了$name:ident标识符捕获,语言服务能识别出这个捕获的标识符对应结构体的字段,因此可以正常显示文档注释。
解决方案
修改b!的定义,将匹配器中的name改为标识符捕获,并添加编译时校验确保只能传入name字段。这样既保留了只匹配name的逻辑,又能让语言服务关联到结构体字段,实现悬停显示文档:
struct Hello { /// Name docs name: String } macro_rules! a { ($name:ident: $value:expr) => { Hello { $name: $value } }; } macro_rules! b { ($name:ident: $expr:expr) => { // 编译时校验:确保传入的字段名是name const _: () = assert!(stringify!($name) == "name"); Hello { $name: $expr } }; } fn main() { let hello_alice = a!(name: String::from("Alice")); let hello_bob = b!(name: String::from("Bob")); // 传入非name字段会触发编译错误,符合需求 // let hello_error = b!(age: String::from("18")); }
如果不需要严格限制只能传入name字段,只是想让name的悬停生效,也可以直接将b!改为通用标识符匹配形式(和a!一致),这样所有字段的悬停都能正常工作。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

