在未实现复制特征时重构"克隆"?



鉴于我在评论中指出的限制,有没有办法摆脱clone()?我真的很想知道在这种情况下是否可以使用借用,在这种情况下无法修改第三方功能签名。

// We should keep the "data" hidden from the consumer
mod le_library {
pub struct Foobar {
data: Vec<i32>  // Something that doesn't implement Copy
}
impl Foobar {
pub fn new() -> Foobar {
Foobar {
data: vec![1, 2, 3],
}
}
pub fn foo(&self) -> String {
let i = third_party(self.data.clone()); // Refactor out clone?
format!("{}{}", "foo!", i)
}
}
// Can't change the signature, suppose this comes from a crate
pub fn third_party(data:Vec<i32>) -> i32 {
data[0]
}
}
use le_library::Foobar;
fn main() {
let foobar = Foobar::new();
let foo = foobar.foo(); 
let foo2 = foobar.foo(); 
println!("{}", foo);
println!("{}", foo2);
}

操场

只要您的foo()方法接受&self,就不可能,因为

pub fn third_party(data: Vec<i32>) -> i32

签名是相当明确的:无论这个third_party函数做什么,它的API都声明它需要自己的Vec实例,按值。这排除了使用任何形式的借用,并且由于foo()通过引用接受self,因此除了克隆之外,您实际上什么都做不了。

此外,据说这个third_party是在没有任何奇怪的不安全黑客的情况下编写的,因此可以非常安全地假设传递到其中的Vec最终被丢弃并解除分配。因此,在不克隆原始Vec的情况下(通过复制内部指针(不安全地创建原始的副本是毫无疑问的 - 如果您这样做,您肯定会获得释放后使用。

虽然你的问题没有说明,但你想保留data的原始价值这一事实是一种自然的假设。如果这个假设可以放宽,并且您实际上可以给出data实例,例如在内部用空向量替换它,那么您可以做几件事:

  1. foo(&self)切换到foo(&mut self),然后您可以轻松地提取data并将其替换为空向量。
  2. 使用CellRefCell存储数据。这样,您可以继续使用foo(&self),但代价是从单元格中提取值并将其替换为某个默认值时进行一些运行时检查。

但是,这两种方法都会导致您丢失原始Vec。使用给定的第三方API,无法解决此问题。

如果您仍然可以以某种方式影响这个外部 API,那么最好的解决方案是将其更改为接受&[i32],这可以通过借用从Vec<i32>轻松获得。

不,你不能摆脱在这里clone的调用。

这里的问题出在第三方库上。由于现在编写了函数third_party,因此确实可以使用&Vec<i32>;它不需要所有权,因为它只是移出一个Copy的值。但是,由于实现不受您的控制,因此没有什么可以阻止维护该功能的人更改它以利用拥有Vec。如果允许它覆盖提供的内存,那么无论它做什么,都可能更容易或需要更少的内存,并且函数编写器将来会这样做。如果不是这种情况,则可能值得建议更改第三方函数的签名并同时依赖clone

最新更新