是否可以将实现特征的所有类型存储在列表中并在该列表上进行迭代?

时间:2019-06-18 19:38:21

标签: generics types rust

我为许多结构(Optional sendBack As Dictionary(Of String, String) = NothingAB等实现了一个特征)

C

我需要一个方法,该方法为该方法调用找到哪个结构返回true。我有代码:

pub trait ApplicableFor: Debug + Default {
    unsafe fn is_applicable_for(from: *mut u8) -> bool
    where
        Self: Sized;
}

在真实的代码中,我有大约20个结构,因此我想将它们存储在某个地方并使用这样的代码以提高可读性:

unsafe fn check_applicable<T: ApplicableFor>(from: *mut u8) -> bool {
    T::is_applicable_for(from, to)
}

unsafe fn find_applicable(from: *mut u8) -> ApplicableFor {
    if check_applicable::<A>(from) {
        A::default()
    } else if check_applicable::<B>(from) {
        B::default()
    } else if check_applicable::<C>(from) {
        C::default()
    } else {
        panic!("Couldn't find appicable");
    }
}

我该怎么做或如何更好地重写它?

1 个答案:

答案 0 :(得分:3)

不,Rust不直接提供您需要的那种元编程功能。即,类型不是存在的具体事物,也不可以放入集合中。

相反,您需要代码生成。

ApplicableFor的简化版本开始,我们可以编写find_applicable的结构化版本:

trait ApplicableFor {
    fn is_applicable_for(from: u8) -> bool;
}

fn find_applicable(from: u8) {
    if <A>::is_applicable_for(from) {
        println!("Using {}", stringify!(A));
        return;
    }

    if <B>::is_applicable_for(from) {
        println!("Using {}", stringify!(B));
        return;
    }

    if <C>::is_applicable_for(from) {
        println!("Using {}", stringify!(C));
        return;
    }

    panic!("Couldn't find any applicable types");
}

一旦建立了结构,就可以使用宏对其进行抽象:

fn find_applicable(from: u8) {
    macro_rules! find_one {
        ($ty:ty) => {
            if <$ty>::is_applicable_for(from) {
                println!("Using {}", stringify!($ty));
                return;
            }
        }
    }

    find_one!(A);
    find_one!(B);
    find_one!(C);

    panic!("Couldn't find any applicable types");
}

如果我们想重复这种“为这种类型的列表做点什么”的概念怎么办?另一个宏:

macro_rules! each_type {
    ($one_type_macro:tt) => {
        $one_type_macro!(A);
        $one_type_macro!(B);
        $one_type_macro!(C);
    };
}

fn find_applicable(from: u8) {
    macro_rules! find_one {
        ($ty:ty) => {
            if <$ty>::is_applicable_for(from) {
                println!("Using {}", stringify!($ty));
                return;
            }
        }
    }

    each_type!(find_one);

    panic!("Couldn't find any applicable types");
}

实施each_type!会带来太多干扰吗?创建一个宏,该宏创建另一个将与另一个宏一起调用的宏:

macro_rules! gen_each_type {
    ($($ty:ty),*) => {
        macro_rules! each_type {
            ($one_type_macro:tt) => {
                $($one_type_macro!($ty);)*
            };
        }
    };
}

gen_each_type![A, B, C];