在接受特征对象的方法中使用相关函数

时间:2018-06-19 01:36:52

标签: rust traits

我正在处理Rust特性LayoutSection,并遇到了一个问题,我必须为这个特性制作两个几乎完全相同的函数:一个是相关函数,一个是那个方法:section_type()section_kind(&self)

理想情况下,我只会使用section_type()关联函数,但LayoutSection无法成为特征对象,除非section_type()具有where Self: Sized子句。

但是我需要在使用特征对象的方法中使用section_type(),因此我被迫创建section_kind(&self),这与section_type()完全相同,但可以调用它特质对象。

我知道这是一个可怕的黑客,并且必须有一些替代方案,但我无法想到其他任何方式来做到这一点。

以下是如何定义和使用这些功能的简化示例:(此处为Rust Playground

fn main() {
    print_generic_info::<Header>(None);
}

fn print_generic_info<S: LayoutSection>(game: Option<Game>) {
    if let Some(s) = game {
        let section = s.get_section::<S>();
    }

    // The reason I wanted to use a type parameter in `Game::get_section`,
    // rather than pass a `SectionType`, is because I'm doing something 
    // like this later on:
    // let section = <S as LayoutSection>::with_offset(...);
}

struct Game;

impl Game {
    fn get_section<S: LayoutSection>(&self) -> Option<&LayoutSection> {
        Some(match <S as LayoutSection>::section_type() {
            SectionType::Header => unimplemented!(),
        })
    }
}

#[derive(Debug)]
enum SectionType {
    Header
}

trait LayoutSection {
    fn section_kind(&self) -> SectionType;
    fn section_type() -> SectionType
    where
        Self: Sized;

    fn print_generic_info(&self) {
        println!("Type: {:?}", self.section_kind());
    }
}

struct Header;

impl LayoutSection for Header {
    fn section_kind(&self) -> SectionType {
        SectionType::Header
    }

    fn section_type() -> SectionType {
        SectionType::Header
    }
}

什么是更好的替代方案?我想使用关联常量来存储SectionType,但是使用那些仍然不允许将LayoutSection用作特征对象。但是类似的东西甚至比section_type()相关函数更好。

1 个答案:

答案 0 :(得分:0)

我能够找到一个使用SectionType枚举而不是使用类型参数的解决方案。我希望有一个名为SectionType::with_offset的关联函数,但我可以向SectionType::with_offset添加SectionType方法。这是更新后的示例:

fn main() {
    print_generic_info(None, &SectionType::Header);
}

fn print_generic_info(game: Option<Game>, section_type: &SectionType) {
    if let Some(s) = game {
        let section = s.get_section(section_type);

        // Now I can do this:
        let other_section = section_type.with_offset(0);
    }
}

struct Game;

impl Game {
    fn get_section(&self, section_type: &SectionType) -> Option<&LayoutSection> {
        Some(match section_type {
            SectionType::Header => unimplemented!(),
        })
    }
}

#[derive(Debug)]
enum SectionType {
    Header
}

impl SectionType {
    fn with_offset(&self, offset: u64) -> Box<LayoutSection> {
        match self {
            SectionType::Header => Box::new(Header),
        }
    }
}

trait LayoutSection {
    fn section_kind(&self) -> SectionType;

    fn print_generic_info(&self) {
        println!("Type: {:?}", self.section_kind());
    }
}

struct Header;

impl LayoutSection for Header {
    fn section_kind(&self) -> SectionType {
        SectionType::Header
    }
}

Link to the Rust Playground