Rust宏中的意外标记

4

我正在尝试编写一个宏,该宏将扩展为一系列自定义结构体的impls。这是我的代码:

pub trait ComponentWise : Clone + Copy {
  fn new(x: f32, y: f32, z: f32) -> Self;
  
  fn x(&self) -> f32;
  fn y(&self) -> f32;
  fn z(&self) -> f32;

  fn has_nans(&self) -> bool {
    f32::is_nan(self.x()) || 
    f32::is_nan(self.y()) || 
    f32::is_nan(self.z())
  }
}

macro_rules! component_wise_impls { 
  ($T:ty) => {
    impl ComponentWise for $T {
      fn new(x: f32, y: f32, z: f32) -> $T {
        let x: $T = $T { vals: [x, y, z] };
        debug_assert!(!x.has_nans());
        x
      }
   };
}

pub struct Vector {
  pub vals: [f32; 3]
}

component_wise_impls!(Vector);

很遗憾,我被告知:

错误: 意外的标记: Vector

let x: $T = $T { vals: [x, y, z] };

我有点惊讶,因为我可以做到 Vector { vals: [x, y, z] },而我认为这正是$T { vals: [x, y, z] }扩展的内容。是否有一种方法在宏中编写此new函数?

1个回答

4

这是有效的:

macro_rules! component_wise_impls {
    ($T:ident) => {
        impl ComponentWise for $T {
            fn new(x: f32, y: f32, z: f32) -> $T {
                let x: $T = $T { vals: [x, y, z] };
                debug_assert!(!x.has_nans());
                x
            }
        }
    }
}

您不能在需要表达式的地方使用 ty
来自此页面:链接 引用如下:

插值$argument_name可以出现在任何与其片段说明符一致的位置(即,如果其被指定为ident,则可以在允许标识符的任何位置使用)。

正如llogiq指出的,您必须实现xyz方法,因此完整的代码如下:
pub trait ComponentWise : Clone + Copy {
  fn new(x: f32, y: f32, z: f32) -> Self;

  fn x(&self) -> f32;
  fn y(&self) -> f32;
  fn z(&self) -> f32;

  fn has_nans(&self) -> bool {
    f32::is_nan(self.x()) || 
    f32::is_nan(self.y()) || 
    f32::is_nan(self.z())
  }
}

macro_rules! component_wise_impls {
    ($T:ident) => {
        impl ComponentWise for $T {
            fn new(x: f32, y: f32, z: f32) -> $T {
                let x: $T = $T { vals: [x, y, z] };
                debug_assert!(!x.has_nans());
                x
            }

            fn x(&self) -> f32 {
                self.vals[0]
            }

            fn y(&self) -> f32 {
                self.vals[1]
            }

            fn z(&self) -> f32 {
                self.vals[2]
            }
        }
    }
}

#[derive(Copy, Clone)]
pub struct Vector {
  pub vals: [f32; 3]
}

component_wise_impls!(Vector);

2
@anjruu:你还需要实现 x/y/z() 函数并让 Vector 实现 CopyClone 才能使其正常工作。 - llogiq

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