我有一个带字段的结构:
struct A {
field: SomeType,
}
Run Code Online (Sandbox Code Playgroud)
给定a &mut A,如何移动值field并交换新值?
fn foo(a: &mut A) {
let mut my_local_var = a.field;
a.field = SomeType::new();
// ...
// do things with my_local_var
// some operations may modify the NEW field's value as well.
}
Run Code Online (Sandbox Code Playgroud)
最终目标相当于一项get_and_set()行动.在这种情况下,我并不担心并发性.
我想在不使用任何克隆的情况下将旧变体的字段移动到新变体时更新枚举变体:
enum X {
X1(String),
X2(String),
}
fn increment_x(x: &mut X) {
*x = match *x {
X::X1(s) => X::X2(s),
X::X2(s) => X::X1(s),
}
}
Run Code Online (Sandbox Code Playgroud)
这并不工作,因为我们不能移动s的&mut X.
请不要建议实现enum X { X1, X2 }和使用struct S { variant: X, str: String }等等.这是一个简化的例子,想象在变体中有许多其他字段,并希望将一个字段从一个变量移动到另一个变体.
我有一个隐藏在后面的Git存储库Mutex:
pub struct GitRepo {
contents: Mutex<GitContents>,
workdir: PathBuf,
}
Run Code Online (Sandbox Code Playgroud)
我想查询它,但最多只查询一次:在查询之后,我想只使用我们第一次得到的结果.存储库具有git2::Repository结果的向量或向量.A Repository是Send但不是Sync.
enum GitContents {
Before { repo: git2::Repository },
After { statuses: Git },
}
struct Git {
statuses: Vec<(PathBuf, git2::Status)>,
}
Run Code Online (Sandbox Code Playgroud)
该GitContents枚举反映了一个事实,我们要么库进行查询,或查询它的结果,但不可能兼顾.
我试图让Rust通过将存储库转换为状态的函数来强制执行此属性,因为它生成状态向量时使用存储库:
fn repo_to_statuses(repo: git2::Repository, workdir: &Path) -> Git {
// Assume this does something useful...
Git { statuses: Vec::new() }
}
Run Code Online (Sandbox Code Playgroud)
但是,我不能让它Mutex玩得很好.到目前为止,我尝试编写一个GitRepo使用谓词查询a的函数P,替换Mutexif中尚未查询的值:
impl GitRepo { …Run Code Online (Sandbox Code Playgroud) 我正在使用gfx-hal,这需要我创建需要使用特定于其类型的函数显式销毁的资源.我想将这些类型的实例存储在结构中,并且我还希望将它们清理到拥有结构的生命周期,而不是手动管理它们的生命周期并且可能在GPU上/驱动程序中有对象永远.
但是,函数destroy族中的所有函数都直接使用类型而不是引用,所以当我尝试从结构中传递它们时,会出现如下错误:
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> src/lib.rs:9:18
|
9 | destroyT(self.member)
| ^^^^^^^^^^^ cannot move out of here
Run Code Online (Sandbox Code Playgroud)
似乎应该有一些解决这个问题的方法,因为我目前处于Drop::drop函数本身,因此self已经"消耗"了.我如何获得这些类型的实例出来self的T,而不是&T?
struct T;
struct S {
member: T,
}
impl Drop for S {
fn drop(&mut self) {
destroyT(self.member)
}
}
// elsewhere, in a library
fn destroyT(t: T) {
//...
}
Run Code Online (Sandbox Code Playgroud) 我有一个结构,我想按值获取、变异然后返回。我还想改变它的泛型类型,因为我使用此状态静态地确保函数调用的正确顺序,以实现安全的 FFI(游乐场):
use core::marker::PhantomData;
struct State1 {}
struct State2 {}
struct Whatever {}
struct X<State> {
a: Whatever,
b: Whatever,
c: Whatever,
_d: PhantomData<State>,
}
impl<State> Drop for X<State> {
fn drop(&mut self) {}
}
fn f(x: X<State1>) -> X<State2> {
let X { a, b, c, _d } = x;
//mutate a, b and c
X {
a,
b,
c,
_d: PhantomData,
} // return new instance
}
Run Code Online (Sandbox Code Playgroud)
因为X实现了Drop,我得到:
use core::marker::PhantomData;
struct State1 …Run Code Online (Sandbox Code Playgroud) 我有以下内容:
enum SomeType {
VariantA(String),
VariantB(String, i32),
}
fn transform(x: SomeType) -> SomeType {
// very complicated transformation, reusing parts of x in order to produce result:
match x {
SomeType::VariantA(s) => SomeType::VariantB(s, 0),
SomeType::VariantB(s, i) => SomeType::VariantB(s, 2 * i),
}
}
fn main() {
let mut data = vec![
SomeType::VariantA("hello".to_string()),
SomeType::VariantA("bye".to_string()),
SomeType::VariantB("asdf".to_string(), 34),
];
}
Run Code Online (Sandbox Code Playgroud)
我现在想调用transform每个元素data并将结果值存回data.现在,我当然可以做类似的事情,data.into_iter().map(transform).collect()但这将分配一个新的Vec.有没有办法在就地执行此操作,重用已分配的内存data?有一次Vec::map_in_place在Rust,但它已被删除了一段时间(我认为在1.4左右).
作为解决方法,我目前添加Dummy-variant SomeType,然后执行以下操作:
for x in …Run Code Online (Sandbox Code Playgroud) 我想将以下Padded类型放入迭代器转换器中:
enum Step<T> {
Before(T),
During(T),
After
}
struct Padded<T> {
step: Step<T>
}
Run Code Online (Sandbox Code Playgroud)
Step(请注意,在我的实际代码中,除了inside之外还有其他东西,因此有额外的从toPadded间接层。)structenum
这个想法是,在每次迭代中,我们总是更改我们的,因此将其中存储的Step内容移动到下一个的构造函数中应该是正确的。但是,我无法让它工作。TStep
简单版本:
impl<T: Iterator> Iterator for Padded<T> {
type Item = Option<T::Item>;
fn next(&mut self) -> Option<Self::Item> {
match &self.step {
Step::Before(start) => {
self.step = Step::During(*start);
Some(None)
},
Step::During(ref mut iter) => {
match iter.next() {
Some(x) => { self.step = Step::During(*iter); Some(Some(x)) },
None => { self.step = Step::After; Some(None) },
} …Run Code Online (Sandbox Code Playgroud) 我正在使用两个独立的功能。
// This structure is not `Clone`.
struct MyStruct;
fn take_owned(s: MyStruct) -> MyStruct {
// Do things
s
}
fn take_mut(s: &mut MyStruct) {
*s = take_owned(s /* problem */);
}
Run Code Online (Sandbox Code Playgroud)
我想了一个解决方案,但我不确定它是否合理:
use std::ptr;
// Temporarily turns a mutable reference into an owned value.
fn mut_to_owned<F>(val: &mut MyStruct, f: F)
where
F: FnOnce(MyStruct) -> MyStruct,
{
// We're the only one able to access the data referenced by `val`.
// This operation simply takes ownership of the …Run Code Online (Sandbox Code Playgroud) 我有一个函数可以获取某些数据的所有权,对其进行破坏性修改,然后返回它。
fn transform(s: MyData) -> MyData {
todo!()
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,我有一个&mut MyData参考。我想transform申请&mut MyData.
fn transform_mut(data_ref: &mut MyData) {
*data_ref = transform(*data_ref);
}
Run Code Online (Sandbox Code Playgroud)
但是,这会导致编译器错误。
error[E0507]: cannot move out of `*data_ref` which is behind a mutable reference
--> src/lib.rs:10:27
|
10 | *data_ref = transform(*data_ref);
| ^^^^^^^^^ move occurs because `*data_ref` has type `MyData`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)
我考虑过使用mem::swap和mem::replace,但它们要求您在取出另一个值之前已经有一些有效的值可以放入参考中。
有什么办法可以做到这一点吗?MyData没有合理的默认值或虚拟值来临时存储在引用中。感觉因为我拥有独占访问权限,所以所有者不应该关心转换,但我的直觉在这里可能是错误的。
我有一个struct Database { events: Vec<Event> }。我想应用一些地图和过滤器events。有什么好的方法可以做到这一点?
这是我尝试过的:
fn update(db: &mut Database) {
db.events = db.events.into_iter().filter(|e| !e.cancelled).collect();
}
Run Code Online (Sandbox Code Playgroud)
这不起作用:
cannot move out of `db.events` which is behind a mutable reference
...
move occurs because `db.events` has type `Vec<Event>`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)
有什么方法可以说服 Rust 编译器我只是暂时获取字段值吗?