对源引用和目标引用可能相同的类型进行操作

Mar*_*ena 5 rust

下面我有一个函数可以处理与source和相同的数据destination相同的数据,也可以处理不同的数据。如果您没有传递源,则它应该将目的地视为源。

\n
use core::ops::IndexMut;\nuse core::ops::Index;\nuse core::marker::PhantomData;\n\nstruct B<\'a, T>{\n    _phantom: PhantomData<&\'a T>\n}\n\nstruct BMut<\'a, T>{\n    _phantom: PhantomData<&\'a mut T>\n}\n\nimpl<\'a, T> Index<T> for B<\'a, T> {\n    type Output = T;\n    fn index(&self, t: T) -> &T {\n        unimplemented!()\n    }\n}\n\nimpl<\'a, T> Index<T> for BMut<\'a, T> {\n    type Output = T;\n    fn index(&self, t: T) -> &T {\n        unimplemented!()\n    }\n}\n\nimpl<\'a, T> IndexMut<T> for BMut<\'a, T> {\n    fn index_mut(&mut self, t: T) -> &mut T {\n        unimplemented!()\n    }\n}\n\nimpl<\'a, T> From<BMut<\'a, T>> for B<\'a, T> {\n    fn from(_e: BMut<\'a, T>) -> Self {\n        B{\n            _phantom: PhantomData\n        }\n    }\n}\n\ntrait A where Self: Sized {\n    fn transform(source: Option<&B<Self>>, destination: &mut BMut<Self>);\n}\n\nimpl A for u64 {\n    fn transform(source: Option<&B<Self>>, destination: &mut BMut<Self>) {\n        let source = match source{\n            Some(source) => source,\n            None => destination.into()\n        };\n        //do a transformation here that reads and writes from destination.\n        //In case we specified a source, then it uses it, otherwise uses destination\n        //as a source. Technically this should be possible because it\'s impossible to pass \n        //a source that is equal to destination\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=15a2cae5c1240890e6f611d79e74​​958f

\n

问题是我无法转换BMutB. 是的,如果未指定源,我可以在每次需要时访问BMut该函数,但如果源有一种类型并且只能将其设置为目标一次,那就更酷了。aB

\n

\xe2\xa3\xbf

\n

标准误

\n
error[E0277]: the trait bound `&B<\'_, u64>: From<&mut BMut<\'_, u64>>` is not satisfied\n  --> src/lib.rs:49:33\n   |\n49 |             None => destination.into()\n   |                                 ^^^^ the trait `From<&mut BMut<\'_, u64>>` is not implemented for `&B<\'_, u64>`\n   |\n   = help: the following implementations were found:\n             <B<\'a, T> as From<BMut<\'a, T>>>\n   = note: required because of the requirements on the impl of `Into<&B<\'_, u64>>` for `&mut BMut<\'_, u64>`\n\n
Run Code Online (Sandbox Code Playgroud)\n

Lag*_*aer 3

我认为这里有多个问题。现在从编译器错误来看,表面问题是转换不起作用,对吧?编译器会告诉你原因。它知道如何将拥有的变成 拥有的BMut,但不知道如何做到这一点以供参考。 B

现在,在您的游乐场示例中,您使用的是幻像数据,但我假设实际上您的结构包含(并拥有!)未实现该Copy特征的实际有趣数据。

那么问题是,要便宜地创建 a ,BBMut需要将这些拥有的值移至新结构中。无论如何,这就是From要做的Into事情。但您无法将共享引用中的内容移出。

另一个问题:借用检查器实际上并不让您编写一个函数,该函数将两个单独的可变引用作为参数,然后使用相同的数据进行调用。我的意思是:

fn some_operation(&mut source: SomeType, &mut dest: SomeType) {
  dest.do_something_mutable(source.get_some_info())
}

fn main() {
  let source_and_dest = SomeType::new();
  
  some_operation(&mut source_and_dest, &mut source_and_dest); // ERROR!
}
Run Code Online (Sandbox Code Playgroud)

编译器会抱怨,因为现在您正在获取同一变量的两个可变引用,这是借用检查器不喜欢的。

那么也许这就是您说“如果您不传递源,它应该将目的地视为源”时的意思?但是,您仍然无法获取目标并从中获取可变引用,从而将其视为源。您实际上必须编写两段逻辑,一种用于源和目标都给定且不同的情况,另一种用于对相同数据进行操作的情况。

也许通过更多关于代码幕后内容的上下文(您的最小可重现示例非常简洁),我们可以提供更具体的帮助。