Add*_*son 5 enums downcast type-safety type-parameter rust
我有以下结构:
#[derive(Debug)]
pub struct Entry {
pub index: usize,
pub name: String,
pub filename_offset: u64,
pub entry_type: EntryType,
}
#[derive(Debug)]
pub enum EntryType {
File {
file_offset: u64,
length: usize,
},
Directory {
parent_index: usize,
next_index: usize,
},
}
Run Code Online (Sandbox Code Playgroud)
Entry是GameCube ROM文件系统表中的一个条目,它描述了一个文件或目录.我定义了各种方法,Entry如Entry::read_filename和Entry::write_to_disk.但是,我有一些方法对常规文件和目录都没有意义.例如,Entry::iter_contents遍历目录的所有子条目.
我希望能够定义某些方法,例如Entry::iter_contents仅针对entry_type某个变体的条目.
我尝试EntryType变成一个特征并制作了一个DirectoryEntryInfo和FileEntryInfo结构,两者都实现了EntryType.
可悲的是,这种方法存在一些问题.我有一个Vec<Entry>其他地方,这种变化将成为Vec<Entry<EntryType>>.使用这样的特质,我也没有办法垂头丧气Entry<EntryList>来Entry<DirectoryEntryInfo>.我也尝试过做一些事情Any,因为这是我所知道的唯一一种在Rust中贬低的方式,但我只能投entry_type,而不是整个Entry本身.
最终,我想最终得到类似的东西:
impl<T: EntryType> Entry<T> {
pub fn as_dir(&self) -> Option<Entry<DirectoryEntryInfo>> { ... }
pub fn as_file(&self) -> Option<Entry<FileEntryInfo>> { ... }
...
}
impl Entry<DirectoryEntryInfo> {
...
}
impl Entry<FileEntryInfo> {
...
}
Run Code Online (Sandbox Code Playgroud)
这样,我可以访问所有条目字段,而无需知道它是否是目录或文件,并且能够将其转换为Entry除了基于类型的方法之外还为我提供所有字段的类型参数如Entry::iter_contents.
有没有像RFC 1450这样的方法有一个很好的方法吗?
我知道枚举变体不是他们自己的类型,不能用作类型参数.我只是在寻找另一种方法来有条件地为结构定义一个方法,并且仍然能够以类似的方式存储这个结构的任何变体Vec.这篇文章非常接近我想要做的.但是,使用它的示例,无法在MyEnum<Bool>不知道Bool是在编译时True还是False在编译时存储.能够垂头丧气像MyEnum<Box<Bool>>到MyEnum<False>可以解决这个问题,但我不知道这样的鲁斯特什么.
不幸的是,您不能完全做到这一点,因为(如问题注释中所述)枚举变体不是类型,并且有关变体的信息不可用于类型系统。
一种可能的方法是将“提升”enum到外层,并让每个变体都包含struct包装共享数据的 a:
struct EntryInfo {
index: usize,
name: String,
filename_offset: u64,
}
pub struct FileEntry {
info: EntryInfo,
file_offset: u64,
length: usize,
}
pub struct DirEntry {
info: EntryInfo,
parent_index: usize,
next_index: usize,
}
pub enum Entry {
File(FileEntry),
Dir(DirEntry),
}
Run Code Online (Sandbox Code Playgroud)
然后您可以按照以下方式轻松定义as_file和:as_dir
impl Entry {
pub fn as_dir(&self) -> Option<&DirEntry> {
match *self {
Entry::Dir(ref d) => Some(d),
_ => None,
}
}
pub fn as_file(&self) -> Option<&FileEntry> {
match *self {
Entry::File(ref f) => Some(f),
_ => None,
}
}
}
Run Code Online (Sandbox Code Playgroud)
这并不理想,因为您之前编写的任何代码Entry现在都需要遵循EntryInfo适当的变体。可以让事情变得更容易的一件事是编写一个辅助方法来查找包装的EntryInfo:
fn as_info(&self) -> &EntryInfo {
match *self {
Entry::Dir(ref d) => &d.info,
Entry::File(ref f) => &f.info,
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以在 的实现中使用self.as_info()而不是.self.infoEntry
| 归档时间: |
|
| 查看次数: |
434 次 |
| 最近记录: |