Rust:泛型必须实现 &xx[...]

Rust: generic must be implement &xx[...]

我正在尝试实现一个通用结构,从一开始就很清楚它的元素 'provider' 必须是稍后支持 &myvar.provider[..] 的类型。但我无法为此找到正确的 Bound。

pub struct MyStruct<T: ??> {  // T must support &x.provider[..]
   pub provider: T,
}

非常感谢您的帮助

更新:扩展示例。我想要实现的目标是:数据块最大可达 10GB。它们可以作为静态 b"aa" 提供,主要用于测试、将文件内容读入内存或映射文件内容。无论提供商如何,在处理数据时我们只使用 &[u8].

//
// A minimal example for my problem
//

use std::str;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::boxed::Box;
use memmap::{MmapOptions, Mmap};

#[derive(Debug)]
pub struct DBFileBuilder<T> {  // what is the correct bound? T must support &x[..]
    pub filename: String,
    pub provider: Option<T>,
    pub startpos: usize,
    // ... several more 
}

pub struct DBFile<'a, T> {  // what is the correct bound? T must support &x[..]
    pub filename: String,
    pub provider: T,
    pub data: &'a [u8],
    // ... several more 
}

impl<T> DBFileBuilder<T> {
    fn default() -> Self {
        Self { 
            filename: String::default(), 
            provider: None,
            startpos: 0,
        }
    }

    pub fn from_bytes(data: &[u8]) -> DBFileBuilder<&[u8]> {
        DBFileBuilder { 
            provider: Some(&data),
            ..DBFileBuilder::default() 
        }
    }

    pub fn read_file(filename: &str) -> Result<DBFileBuilder<Box<[u8]>>, Box<dyn Error>> {
        let mut file = File::open(&filename)?;
        let fsize = file.metadata()?.len();

        let mut provider = vec![0_u8; fsize as usize].into_boxed_slice();
        let n = file.read(&mut provider)?;

        Ok(DBFileBuilder {
            filename: filename.to_string(),
            provider: Some(provider),
            ..DBFileBuilder::default()
        })
    }

    pub fn mmap_file(filename: &str) -> Result<DBFileBuilder<Mmap>, Box<dyn Error>> {
        let file = File::open(&filename)?;
        let provider = unsafe { MmapOptions::new().map(&file)? };

        Ok(DBFileBuilder {
            filename: filename.to_string(),
            provider: Some(provider),
            ..DBFileBuilder::default()
        })
    }

    pub fn init(&mut self) {
    }

    pub fn build<'a>(self) -> DBFile<'a, T> {
        let provider = self.provider.expect("Provider not initialized");
        self.init();
        let data = &provider[self.startpos ..];

        DBFile {
            filename: self.filename,
            provider,
            data,
        }
    }
}

impl<'a, T> DBFile<'a, T> {
    pub fn run(&self) { 
        return self.process(self.data)
    } 

    pub fn process(&self, data: &[u8]) { 
        println!("data: {:?}", &data); 
    }
}

通过使用封闭范围获取字节来索引绑定的必要特征是Index<Range<usize>, Output=[u8]>。 您可能还想按无限范围进行索引:

pub struct MyStruct<T>
where T: Index<Range<usize>, Output=[u8]>
   + Index<RangeTo<usize>, Output=[u8]>
   + Index<RangeFrom<usize>, Output=[u8]>
   + Index<RangeFull, Output=[u8]>
{
    pub provider: T,
}

不幸的是,这些边界目前无法在使用 MyStruct 的签名中推断出来(尽管我相信这正在进行中),这可能会变得非常笨拙。如果你使用 Nightly,你可以定义一个 trait alias (RFC1733) 来减少冗长。

也就是说,您需要重新考虑该示例,因为它行不通:例如在 build() 中,data 不能成为返回的 DBFile 的一部分,因为它指向一个生存时间不够长的局部变量。