gpt4 book ai didi

reference - 如何避免在 Rust 中为可变和不可变引用编写重复的访问器函数?

转载 作者:行者123 更新时间:2023-11-29 07:51:50 24 4
gpt4 key购买 nike

有几次,我遇到过可变引用和不可变引用都需要访问器方法的情况。

对于大约 3 行,复制逻辑不是问题,但是当逻辑变得更复杂时,复制粘贴大块代码就不好了。

我希望能够为两者重复使用代码。

Rust 是否提供了一些比复制粘贴代码或使用 unsafe 转换更好地处理这种情况的方法?

例如:

impl MyStruct {
pub fn get_foo(&self) -> &Bar {
// ~20 lines of code
// --- snip ---
return bar;
}
pub fn get_foo_mut(&mut self) -> &mut Bar {
// ~20 lines of code
// (exactly matching previous code except `bar` is mutable)
// --- snip ---
return bar;
}
}

这里是一个代码库的更详细的摘录,其中一个不可变的返回参数被强制转换为可变的,以支持一个函数的不可变和可变版本。这使用了包装指针类型(ConstPMutP 用于不可变和可变引用),但函数的逻辑应该很清楚。

pub fn face_vert_share_loop<V, F>(f: F, v: V) -> LoopConstP
where V: Into<VertConstP>,
F: Into<FaceConstP>
{
into_expand!(f, v);

let l_first = f.l_first.as_const();
let mut l_iter = l_first;
loop {
if l_iter.v == v {
return l_iter;
}

l_iter = l_iter.next.as_const();
if l_iter == l_first {
break;
}
}

return null_const();
}
pub fn face_vert_share_loop_mut(f: FaceMutP, v: VertMutP) -> LoopMutP {
let l = face_vert_share_loop(f, v);
return unsafe {
// Evil! but what are the alternatives?
// Perform an unsafe `const` to `mut` cast :(
// While in general this should be avoided,
// its 'OK' in this case since input is also mutable.
l.as_mut()
};
}

最佳答案

( Playground 链接到使用 type parametersassociated types 的解决方案)

在这种情况下,&T&mut T 只是两种不同的类型。在不同类型上通用的代码(在编译时和运行时)是使用特征在 Rust 中惯用地编写的。例如,给定:

struct Foo { value: i32 }
struct Bar { foo: Foo }

假设我们想为 BarFoo 数据成员提供一个通用访问器。访问器应该在 &Bar&mut Bar 上工作,适本地返回 &Foo&mut Foo。所以我们写一个trait FooGetter

trait FooGetter {
type Output;
fn get(self) -> Self::Output;
}

其工作是对我们拥有的特定类型的 Bar 进行通用化。它的 Output 类型将取决于 Bar,因为我们希望 get 有时返回 &Foo 有时返回 &mut Foo 。另请注意,它使用 Self 类型的 self。因为我们希望 get&Bar&mut Bar 上通用,所以我们需要为两者实现 FooGetter,这样Self 具有适当的类型:

// FooGetter::Self == &Bar
impl<'a> FooGetter for &'a Bar {
type Output = &'a Foo;
fn get(self) -> Self::Output { & self.foo }
}

// FooGetter::Self == &mut Bar
impl<'a> FooGetter for &'a mut Bar {
type Output = &'a mut Foo;
fn get(mut self) -> Self::Output { &mut self.foo }
}

现在我们可以轻松地在通用代码中使用 .get() 来获取 &&mutFoo 的引用> 来自 &Bar&mut Bar(只需要 T: FooGetter)。例如:

// exemplary generic function:
fn foo<T: FooGetter>(t: T) -> <T as FooGetter>::Output {
t.get()
}

fn main() {
let x = Bar { foo: Foo {value: 2} };
let mut y = Bar { foo: Foo {value: 2} };

foo(&mut y).value = 3;
println!("{} {}\n", foo(&x).value, foo(&mut y).value);
}

请注意,您还可以为 Bar 实现 FooGetter,因此 get&T 是通用的,&mut TT 本身(通过将其移入)。这实际上就是 .iter() 方法在标准库中的实现方式,以及为什么它总是独立于其调用的参数的引用性做“正确的事情”。

关于reference - 如何避免在 Rust 中为可变和不可变引用编写重复的访问器函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51301170/

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