Rust 宏中的特征可选(类型ExampleType = xxx)

问题描述 投票:0回答:1

我想要一个宏,帮助我生成特征,如果没有给出,关联类型

ExtraData
将被分配给单位类型。

pub trait TestTrait {
    type ExtraData;
    fn test(&self, _state: &Self::ExtraData) {}
    fn test_a(&self, _state: Self::ExtraData) {}
}

pub struct Data;

#[macro_export]
macro_rules! type_or_unit {
    () => { () };
    ($name:ty) => { $name };
}

#[macro_export]
macro_rules! expand {
    {
        pub struct $example_type:ident;

        impl TestTrait for $example_type1:ident {
            $(type ExtraData = $extra_state:ty;)?
            $($impls:tt)*
        }
    } => {
        pub struct $example_type;

        impl TestTrait for $example_type1 {
            type ExtraData = $crate::type_or_unit! {$( $extra_state )?};
            $($impls)*
        }
    }
}


fn main() {
    expand!{
        pub struct Test;

        impl TestTrait for Test {
            type ExtraData = ();
        }
    }
}

rust 宏无法扩展,因为: ```错误:调用宏时出现局部歧义

expand
:多个解析选项:内置NTs tt('impls')或1个其他选项。 --> src/main.rs:41:13 | 41 | 41 输入额外数据 = ();

Why does this happen and how to solve the issue?
rust rust-macros
1个回答
0
投票

这感觉像是一种奇怪的使用声明性宏的方式。您可以通过直接在

type_or_unit!
上匹配而不是在
expand!
处匹配模式来解决这个问题,这意味着制作两个模式块,一个带有
type ExtraData = $extra_state:ty;
,一个没有。

但是,如果您详细说明您想要实现什么,为什么您的类型定义位于宏模式匹配内部,那就太好了?如果所有方法都已在特征中实现,为什么不只采用类型和额外的数据类型。如果您需要手动实现特征内部的某些功能,为什么选择编写宏来生成 1 行代码。

为什么不

pub trait TestTrait {
    type ExtraData;
    fn test(&self, _state: &Self::ExtraData) {}
    fn test_a(&self, _state: Self::ExtraData) {}
}

macro_rules! impl_TestTrait {
    ($t:ty, $extra:ty) => {
        impl TestTrait for $t {
            type ExtraData = $extra;
        }
    };
    ($t:ty) => {
        impl_TestTrait!($t, ());
    }
}

struct Test1;
impl_TestTrait!(Test1, i32);

struct Test2;
impl_TestTrait!(Test2);

fn main() {}
cargo expand
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
pub trait TestTrait {
    type ExtraData;
    fn test(&self, _state: &Self::ExtraData) {}
    fn test_a(&self, _state: Self::ExtraData) {}
}
struct Test1;
impl TestTrait for Test1 {
    type ExtraData = i32;
}
struct Test2;
impl TestTrait for Test2 {
    type ExtraData = ();
}
fn main() {}

根据您的想法解决问题

pub trait TestTrait {
    type ExtraData;
    fn test(&self, _state: &Self::ExtraData) {}
    fn test_a(&self, _state: Self::ExtraData) {}
}

pub struct Data;

#[macro_export]
macro_rules! expand {
    {
        pub struct $example_type:ident;

        impl TestTrait for $example_type1:ident {
            type ExtraData = $extra_state:ty;
            $($impls:tt)*
        }
    } => {
        pub struct $example_type;

        impl TestTrait for $example_type1 {
            type ExtraData = $extra_state;
            $($impls)*
        }
    };
    {
        pub struct $example_type:ident;

        impl TestTrait for $example_type1:ident {
            $($impls:tt)*
        }
    } => {
        pub struct $example_type;

        impl TestTrait for $example_type1 {
            type ExtraData = ();
            $($impls)*
        }
    }
}

expand!{
    pub struct Test1;
    
    impl TestTrait for Test1 {
        type ExtraData = i32;
    }
}
expand!{
    pub struct Test2;
    
    impl TestTrait for Test2 {
    }
}
cargo expand
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
pub trait TestTrait {
    type ExtraData;
    fn test(&self, _state: &Self::ExtraData) {}
    fn test_a(&self, _state: Self::ExtraData) {}
}
pub struct Data;
pub struct Test1;
impl TestTrait for Test1 {
    type ExtraData = i32;
}
pub struct Test2;
impl TestTrait for Test2 {
    type ExtraData = ();
}
fn main() {}
© www.soinside.com 2019 - 2024. All rights reserved.