gpt4 book ai didi

rust - 可变借入带清理的两部分

转载 作者:行者123 更新时间:2023-12-03 11:31:34 25 4
gpt4 key购买 nike

我有一些对象,我想通过可变借用将它们分成两部分,然后在拆分引用超出范围时将它们组合回原始对象。

下面的简化示例适用于 Count包含单个 i32 的结构,我们想将其分成两个 &mut i32 s,他们都被合并回原来的 Count当两个可变引用超出范围时。

我在下面采用的方法是使用中间对象 CountSplit它持有对原始 Count 的可变引用对象并具有 Drop trait 实现了重新组合逻辑。

这种方法感觉很笨拙。特别是,这很尴尬:

let mut ms = c.make_split();
let (x, y) = ms.split();

在一行中执行此操作,例如 let (x, y) = c.make_split().split();不允许,因为中间对象必须有更长的生命周期。理想情况下,我可以做 let (x, y) = c.magic_split(); 之类的事情。并避免完全暴露中间对象。

有没有办法做到这一点,不需要做两个 let的每一次,还是以其他方式来解决这种更惯用的模式?
#[derive(Debug)]
struct Count {
val: i32,
}

trait MakeSplit<'a> {
type S: Split<'a>;
fn make_split(&'a mut self) -> Self::S;
}

impl<'a> MakeSplit<'a> for Count {
type S = CountSplit<'a>;
fn make_split(&mut self) -> CountSplit {
CountSplit {
top: self,
second: 0,
}
}
}

struct CountSplit<'a> {
top: &'a mut Count,
second: i32,
}

trait Split<'a> {
fn split(&'a mut self) -> (&'a mut i32, &'a mut i32);
}

impl<'a, 'b> Split<'a> for CountSplit<'b> {
fn split(&mut self) -> (&mut i32, &mut i32) {
(&mut self.top.val, &mut self.second)
}
}

impl<'a> Drop for CountSplit<'a> {
fn drop(&mut self) {
println!("custom drop occurs here");
self.top.val += self.second;
}
}

fn main() {
let mut c = Count { val: 2 };
println!("{:?}", c); // Count { val: 2 }

{
let mut ms = c.make_split();
let (x, y) = ms.split();
println!("split: {} {}", x, y); // split: 2 0

// each of these lines correctly gives a compile-time error
// c.make_split(); // can't borrow c as mutable
// println!("{:?}", c); // or immutable
// ms.split(); // also can't borrow ms

*x += 100;
*y += 5000;
println!("split: {} {}", x, y); // split: 102 5000
} // custom drop occurs here

println!("{:?}", c); // Count { val: 5102 }
}

playground :

最佳答案

我不认为像你这样的临时值的引用可以在今天的 Rust 中工作。

如果有帮助,如果你特别想用两个 &mut i32 调用一个函数像您在评论中提到的参数,例如

fn foo(a: &mut i32, b: &mut i32) {
*a += 1;
*b += 2;
println!("split: {} {}", a, b);
}

如果您的链接有效,您已经可以使用与您的链接数量相同的行数来做到这一点。

使用链接,您可以调用
let (x, y) = c.make_split().split();
foo(x, y);

如果你只是省略到元组的转换,它看起来像这样:
let mut ms = c.make_split();
foo(&mut ms.top.val, &mut ms.second);

你可以让它更漂亮一点,例如存储对 val 的可变引用直接在 CountSplitfirst , 使其变为 foo(&mut ms.first, &mut ms.second); .如果你想让它感觉更像一个元组,我想你可以使用 DerefMut能够写 foo(&mut ms.0, &mut ms.1); .

或者,您当然可以将其表述为采用函数的函数
impl Count {
fn as_split<F: FnMut(&mut i32, &mut i32)>(&mut self, mut f: F) {
let mut second = 0;
f(&mut self.val, &mut second);
self.val += second;
}
}

然后打电话
c.as_split(foo);

关于rust - 可变借入带清理的两部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62390590/

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