gpt4 book ai didi

rust - 如何指定 AsRef 的生命周期?

转载 作者:行者123 更新时间:2023-11-29 08:07:39 26 4
gpt4 key购买 nike

我正在尝试编写一个连接两个可迭代对象的函数,这两个可迭代对象的项目可以转换为 OsStr 引用,并且在尝试指定引用的生命周期时遇到了巨大的困难。

use std::convert::AsRef;
use std::ffi::OsStr;
use std::marker::PhantomData;

#[derive(Clone, Debug)]
#[must_use = "join_args is lazy and does nothing unless consumed"]
pub struct JoinArgs<'a, A: 'a, B: 'a> {
a: A,
b: B,
state: JoinState,

phantomA: PhantomData<&'a A>,
phantomB: PhantomData<&'a B>,
}

#[derive(Clone, Debug)]
enum JoinState {
Both,
Front,
Back,
}

/// Chains two iterable argument lists.
pub fn join_args<'a, I1, S1, I2, S2>(iter1: I1, iter2: I2) -> JoinArgs<'a, I1::IntoIter, I2::IntoIter>
where
I1: IntoIterator<Item = S1>,
S1: AsRef<OsStr> + 'a,
I2: IntoIterator<Item = S2>,
S2: AsRef<OsStr> + 'a
{
let a = iter1.into_iter();
let b = iter2.into_iter();
JoinArgs{a, b, state: JoinState::Both, phantomA: PhantomData, phantomB: PhantomData}
}

impl<'a, A, SA, B, SB> Iterator for JoinArgs<'a, A, B>
where
A: Iterator<Item = SA>,
SA: AsRef<OsStr> + 'a,
B: Iterator<Item = SB>,
SB: AsRef<OsStr> + 'a
{
type Item = &'a OsStr;

fn next(&mut self) -> Option<Self::Item> {
// All throughout here, I'm getting E0597 errors.
match self.state {
JoinState::Both => match self.a.next() {
Some(x) => Some(x.as_ref()),
None => {
self.state = JoinState::Back;
self.b.next().map(|x| x.as_ref())
}
},
JoinState::Front => self.a.next().map(|x| x.as_ref()),
JoinState::Back => self.b.next().map(|x| x.as_ref()),
}
}
}

我正在尝试清理我使用 mapchain 强制转换类型的代码(如下面的测试) .如果有更好的方法来做到这一点,我会洗耳恭听。 :)

#[cfg(test)]
mod tests {
use super::*;

use std::ffi::OsString;

#[test]
fn test_join_args() {
let a = &[OsStr::new("abc"), OsStr::new("def")];
let b = vec![OsString::from("ghi")];
let result: Vec<&OsStr> = join_args(a, &b).collect();
assert_eq!(result, [
OsStr::new("abc"),
OsStr::new("def"),
OsStr::new("ghi"),
]);
}
}

(这是在 Rust 稳定版本 1.23.0 上)

最佳答案

你没有

AsRef是一个特征,它的定义是固定的:

pub trait AsRef<T>
where
T: ?Sized,
{
fn as_ref(&self) -> &T;
}

只能用于获取一个事物的引用并获得另一个具有相同生命周期的引用。

您的代码将允许 Iterator<Item = OsString> :

use std::ffi::{OsStr, OsString};

fn proof<'a, I>(_: I)
where
I: Iterator,
I::Item: AsRef<OsStr> + 'a,
{}

fn main() {
proof(vec![OsString::new()].into_iter());
}

如果您随后调用 AsRef在这个项目上,你会引用一些不超出功能的东西。但是,您正试图返回该引用,这将是无效的。因此,Rust 阻止了你引入内存不安全;万岁!

这与 How to use the lifetime on AsRef 完全相同


好消息是你可以表达你想要的,你只需要声明你的迭代器返回引用:

impl<'a, A, B, S1, S2> Iterator for JoinArgs<'a, A, B>
where
A: Iterator<Item = &'a S1>,
S1: AsRef<OsStr> + 'a,
B: Iterator<Item = &'a S2>,
S2: AsRef<OsStr> + 'a,
{
// ...
}

顺便说一句,您不需要 PhantomData或结构上的生命周期:

use std::convert::AsRef;
use std::ffi::OsStr;

#[derive(Clone, Debug)]
#[must_use = "join_args is lazy and does nothing unless consumed"]
pub struct JoinArgs<A, B> {
a: A,
b: B,
state: JoinState,
}

#[derive(Clone, Debug)]
enum JoinState {
Both,
Front,
Back,
}

/// Chains two iterable argument lists.
pub fn join_args<I1, I2>(iter1: I1, iter2: I2) -> JoinArgs<I1::IntoIter, I2::IntoIter>
where
I1: IntoIterator,
I2: IntoIterator,
{
JoinArgs {
a: iter1.into_iter(),
b: iter2.into_iter(),
state: JoinState::Both,
}
}

impl<'a, A, B, S1, S2> Iterator for JoinArgs<A, B>
where
A: Iterator<Item = &'a S1>,
S1: AsRef<OsStr> + 'a,
B: Iterator<Item = &'a S2>,
S2: AsRef<OsStr> + 'a,
{
type Item = &'a OsStr;

fn next(&mut self) -> Option<Self::Item> {
match self.state {
JoinState::Both => match self.a.next() {
Some(x) => Some(x.as_ref()),
None => {
self.state = JoinState::Back;
self.b.next().map(AsRef::as_ref)
}
},
JoinState::Front => self.a.next().map(AsRef::as_ref),
JoinState::Back => self.b.next().map(AsRef::as_ref),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

use std::ffi::OsString;

#[test]
fn test_join_args() {
let a = &[OsStr::new("abc"), OsStr::new("def")];
let b = vec![OsString::from("ghi")];
let result: Vec<&OsStr> = join_args(a, &b).collect();
assert_eq!(
result,
[OsStr::new("abc"), OsStr::new("def"), OsStr::new("ghi"),]
);
}
}

另见:

关于rust - 如何指定 AsRef 的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48734211/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com