如何将 Vec<&mut T> 转换为 Vec<&T>?

4

我有一个可变引用的向量:

struct T;
let mut mut_vec: Vec<&mut T> = vec![];

我该如何将它(的一个副本)传递给一个接受不可变引用向量的函数?
fn cool_func(mut immut_vec: Vec<&T>) {}

1
是的,但这会移动可变引用,因此您将无法保留原始向量。 - mcarton
1
你认为为什么需要这个?引用向量本身就很棘手,但是尝试同时拥有几个指向同一元素的不同可变性的引用向量似乎很奇怪。 - mcarton
@mcarton 在一个循环中,我正在运行一个函数来检查哪个资源剩余的时间最长(该函数),然后从该资源中减去特定任务所需的时间(以及其他事项)。我只需要将此副本传递到函数中,因为该函数会改变它所给出的向量。 - wizzwizz4
1
这对我来说看起来像是一个 XY 问题。我建议您提出一个单独的问题,并提供一个更具代表性的示例,说明您想要实现什么 - 我的直觉是可能有一种更“Rust-y”的方法来解决它。 - Joe Clay
@JoeClay 我在这里发布了“X”,尽管标题很糟糕,而且我也不确定要使用哪些标签。 - wizzwizz4
显示剩余2条评论
2个回答

5

您可以取消引用并重新借用可变引用,然后将它们添加到新的 Vec 中:

fn main() {
    let mut st = String::new();

    let mut_vec = vec![&mut st];
    let immut_vec = mut_vec.into_iter().map(|x| &*x).collect();

    cool_func(immut_vec);
}

fn cool_func(_: Vec<&String>) {}

注意,这会消耗原始的Vec - 你无法绕过这个问题,因为如果原始的Vec仍然存在,那么您将同时拥有可变和不可变引用相同的数据片段,这是编译器不允许的。


有没有一种方法可以向编译器保证,在不可变引用的生命周期内,我不会使用可变引用? - wizzwizz4
你不能同时拥有可变引用和不可变引用。有一些包装类型可以将此强制转换为运行时(RefCellMutex等),但它们是最后的选择。 - Joe Clay
1
你真的无法绕过这个问题 — 为什么呢 - Shepmaster
尽管这似乎是明确的重新分配,但事实证明,只要优化级别至少为2,LLVM将会优化掉这种分配:https://godbolt.org/z/rT56WrbM9 - undefined

1
如果你需要实际转换,请参见Joe Clay的答案。然而,你可能不需要在第一时间进行转换!
与其改变参数,不如改变函数使其接受可变和不可变引用。这里我们使用Borrow来抽象处理两者:
use std::borrow::Borrow;

fn main() {
    let mut st = String::new();

    let mut_vec = vec![&mut st];
    cool_func(mut_vec);

    let immut_vec = vec![&st];
    cool_func(immut_vec);
}

fn cool_func<S>(_: Vec<S>)
where
    S: Borrow<String>,
{
}

另请参阅:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接