我有下面的类型定义:
pub struct UTF8Chars {
bytes: Peekable<Box<dyn Iterator<Item = u8>>>,
}
现在我想知道如何实际创建这个结构体的示例。
我试过 (是的,如果这是一个重要的细节,这是在trait实现中):
impl<'a> ToUTF8Chars for &'a str {
fn utf8_chars(self) -> UTF8Chars {
let bytes = Box::new(self.bytes()).peekable();
UTF8Chars { bytes }
}
}
这给了我一个错误:
expected struct `Peekable<Box<(dyn Iterator<Item = u8> + 'static)>>`
found struct `Peekable<Box<std::str::Bytes<'_>>>`
- 一个月一次 *
请原谅我尝试了一些奇怪的东西,但我还没有掌握这种复杂的特性的窍门。据我所知,rust-analyzer告诉我Bytes
实际上是impl Iterator<Item = u8>
。所以,我接下来尝试的是先铸造它:
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
UTF8Chars { bytes: bytes.peekable() }
这是可行的,但现在借位检查员抱怨说:
impl<'a> ToUTF8Chars for &'a str {
-- lifetime `'a` defined here
fn utf8_chars(self) -> UTF8Chars {
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`
我不太确定这里有什么超出了范围......据我所知,我拥有.bytes()
的结果(我还尝试了一个额外的.clone()
,以防假设不正确),我拥有Box
,Box
传递给Peekable
,最后Peekable
被传递给UTF8Chars
。这里到底是什么问题?为什么我需要比static
活得更长...?
我发现这个问题似乎相似,可悲的是没有答案:Peekable of an Iterator in struct.
我为什么要这么做?
嗯,主要是因为我不太关心,或者说不能关心底层数据到底是什么,我只需要知道我可以.peek()
,和.next()
等等,这是因为有时候我想给self.bytes
赋不同的东西,比如Chain<...>
,或者Copied<...>
,而不是简单的vec::IntoIter<...>
。
如果有其他的方法,我很乐意听到。
2条答案
按热度按时间ztigrdn81#
所以,接下来我试着先选角:
在这种情况下,这是正确的做法,尽管我会在
let
上而不是在as
上编写类型注解。特别是,必须存在一个点,在该点上,从
Box<Bytes>
到Box<dyn Iterator<Item = u8>>
的 *unsizing concression * 发生,并且该点必须在Box
包含在其他内容之前(因为它实际上产生了一个不同的Box
,一个添加了vtable指针的Box
)。在某些情况下,仅
as _
(未指定类型)就足以提示编译器不立即得出该类型与传入类型相同的结论。我不太确定什么超出了范围...
每一个trait对象(
dyn
)类型都有一个生命期,通常是隐式的,这个生命期指定了该类型的示例被保证有效的时间长度--或者,从相反的Angular 来看,trait对象被允许借用/包含什么引用。当你没有指定那个生存期,trait对象在
Box
中,生存期省略规则会使那个生存期成为'static
,这就是为什么你会有一个错误:你试图把一个Bytes<'a>
放到一个需要'static
的地方。为了允许你的装箱迭代器借用,你必须定义类型和traits有一个生存期。
如果你不想添加生存期,那么你只能使用拥有迭代器(例如
String::into_bytes(s).into_iter()
)。有了生存期,你可以同时使用拥有迭代器和借用迭代器。2o7dmzc52#
问题是
dyn Trait
类型实际上默认为dyn Trait + 'static
,这意味着它们不允许借用任何数据。这对您来说是个问题,因为通过在&'a str
上调用bytes()
返回的迭代器借用了str
,因此不能比'a
更有效。但是'a
并不比'static
更有效,所以您不能'不要把它变成dyn Iterator + 'static
。正如您可能已经猜到的,这里的解决方案是添加一些更通用的生存期界限,首先添加到结构体:
然后是特质:
不过,根据您的具体用例,使用借来的接收器可能更好:
我敢肯定,在某些情况下,这两个是不一样的(对象安全,可能吗?),但我不能针点一个特定的情况下了我的头上。
最后是实施:
或
ToUTF8Chars
的替代版本。