print-6ren">
gpt4 book ai didi

rust - 包装任意数量类型的宏

转载 作者:行者123 更新时间:2023-11-29 08:15:43 33 4
gpt4 key购买 nike

是否可以编写一个宏来定义一个封装了任意数量(不同)输入类型的枚举?我想做一种类型级别的匹配。

type_switch!(i32 => println!("integer"), f32 => println!("float"), Foo => println!("foo"))

这将扩展为:

{
enum Wrapper {
Variant1(i32),
Variant2(f32),
Variant3(Foo),
}

// impl From<i32>, From<f32>, From<Foo> for Wrapper

|x: Wrapper| match x {
Wrapper::Variant1(x) => println!("integer"),
Wrapper::Variant2(x) => println!("float"),
Wrapper::Variant3(x) => println!("foo"),
}
}

这样我就可以这样写了

let switch = type_switch!(i32 => println!("integer"), f32 => println!("float"), Foo => println!("foo"));
switch(32.into()); // prints "integer"
switch(24.0.into()); // prints "float"

最佳答案

在宏中定义一个特征并为每种类型实现它:

macro_rules! type_switch {
($($ty: ty => $expr: expr),+) => {{
trait TypeMatch {
fn type_match(self);
}
$(
impl TypeMatch for $ty {
fn type_match(self) {
$expr
}
}
)+
TypeMatch::type_match
}}
}

请注意,第一次调用该函数时,编译器将绑定(bind)类型,以便后续调用必须是同一类型:

struct Foo;

fn main() {
let s = type_switch! {
i32 => { println!("i32"); },
f32 => { println!("f32"); },
Foo => { println!("Foo"); }
};

s(0);
s(Foo); // Error!
}

如果您需要能够使用不同的类型来调用它,这可以通过使用特征对象进行动态调度来解决(以很小的成本):

macro_rules! type_switch {
($($ty: ty => $expr: expr),+) => {{
trait TypeMatch {
fn type_match(&self);
}
$(
impl TypeMatch for $ty {
fn type_match(&self) {
$expr
}
}
)+
|value: &dyn TypeMatch| {
value.type_match()
}
}}
}

struct Foo;

fn main() {
let s = type_switch! {
i32 => { println!("i32"); },
f32 => { println!("f32"); },
Foo => { println!("Foo"); }
};

s(&0);
s(&Foo);
}

另请注意,您必须传递引用而不是值。

关于rust - 包装任意数量类型的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53695400/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com