簡體   English   中英

是否可以將實現特征的所有類型存儲在列表中並在該列表上進行迭代?

[英]It is possible to store all types implementing a trait in a list and iterate over that list?

我為許多結構( ABC等)實現了一個特征:

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

我需要一個方法來找到哪個結構為此方法調用返回true。 我有代碼:

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");
    }
}

在實際的代碼中,我有大約20個結構,因此我想將它們存儲在某個地方,並使用如下代碼來提高可讀性:

unsafe fn find_applicable(from: *mut u8) -> ApplicableFor {
    for T in list {
        if check_applicable::<T>(from) {
            T::default()
        }
    }
    panic!("Couldn't find appicable");
}

我該怎么做或如何更好地重寫呢?

不,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!的實現來說太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];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM