当基于类型实现宏时,为什么需要在<$a>中使用尖括号?

9
我可以编写一个宏来接受这样的类型:
trait Boundable<A> {
    fn max_value() -> A;
}

impl Boundable<u8> for u8 {
    fn max_value() -> u8 { u8::MAX }
}

当我将impl转换为宏时,为什么需要像这样用尖括号括起来类型本身?
macro_rules! impl_boundable {
    ($a:ty) => {
        impl Boundable<$a> for $a {
            fn max_value() -> $a { <$a>::MAX }
        }
    };
}

impl_boundable!(i8);

尤其是 <$a>::MAX。没有它,编译器会报错 missing angle brackets in associated item path。让我困惑的是为什么宏代码需要与非宏代码不同。

playground


我猜这是为了引用类型或其他不确定性而设置的保护,因为<&T>::func()&T::func()是不同的东西。 - kmdreko
嗯,我不这么认为——它匹配的是 ty,而不是 expr,所以即使它是 &T,也无法重新解析为(部分)表达式。 - trent
1个回答

15
句法为_path_::item,而不是_type_::item。有效的路径包括标识符和对于类型T<T>
在中,被允许是因为它是一个标识符,而不是一个类型。不允许[u8; 1]::item
如果你的宏接收$a:ident,而不是$a:ty,那么对于也是标识符的类型如u8,它将按原样工作。但是,如果接收一个类型$a:ty,从类型创建路径的通用方法是使用尖括号<$a>
对于你的宏直接接收路径也是一种选择:$a:path。但是,你可能会遇到bug #48067:解析器无法确定如何从较小的路径段组合路径。在use $a as base; base::MAX的票据中有这种情况的解决办法。

有道理。我想知道允许将 u8 用作路径的特殊情况是否有文档记录?我使用 $a:path 进行了测试,但虽然宏编译通过,但我无法将裸的 u8 传递给它,所以它必须在某种程度上是上下文相关的。 - trent
我敢打赌你遇到了48067。我会进行编辑。 - Jeff Garrett
是的,那一定是它。我今天学到了两件事。 - trent
我也是。虽然我没有找到直接相关的文档,但是这些问题确实有所帮助(https://github.com/rust-lang/rust/issues/52307以及从那里链接的问题/拉取请求)。 - Jeff Garrett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接