简体   繁体   English

未实现 Copy trait 时重构出 `clone`?

[英]Refactoring out `clone` when Copy trait is not implemented?

Is there a way to get rid of clone() , given the restrictions I've noted in the comments?鉴于我在评论中指出的限制,有没有办法摆脱clone() I would really like to know if it's possible to use borrowing in this case, where modifying the third-party function signature is not possible.我真的很想知道在这种情况下是否可以使用借用,在这种情况下无法修改第三方函数签名。

// 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);
}

playground 操场

No, you can't get rid of the call to clone here.不,你不能在这里摆脱对clone的调用。

The problem here is with the third-party library.这里的问题在于第三方库。 As the function third_party is written now, it's true that it could be using an &Vec<i32> ;由于现在编写了函数third_party ,它确实可以使用&Vec<i32> it doesn't require ownership, since it's just moving out a value that's Copy .它不需要所有权,因为它只是移出一个值为Copy However, since the implementation is outside of your control, there's nothing preventing the person maintaining the function from changing it to take advantage of owning the Vec .但是,由于实现不受您的控制,因此没有什么可以阻止维护该功能的人更改它以利用拥有Vec优势。 It's possible that whatever it is doing would be easier or require less memory if it were allowed to overwrite the provided memory, and the function writer is leaving the door open to do so in the future.如果允许覆盖所提供的内存,那么无论它在做什么,它都可能会更容易或需要更少的内存,并且函数编写者在将来会为这样做而敞开大门。 If that's not the case, it might be worth suggesting a change to the third-party function's signature and relying on clone in the meantime.如果情况并非如此,则可能值得建议更改第三方函数的签名并同时依赖clone

As long as your foo() method accepts &self , it is not possible, because the只要你的foo()方法接受&self ,这是不可能的,因为

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

signature is quite unambiguous: regardless of what this third_party function does, it's API states that it needs its own instance of Vec , by value.签名非常明确:不管这个third_party函数做什么,它的 API 声明它需要自己的Vec实例,按值。 This precludes using borrowing of any form, and because foo() accepts self by reference, you can't really do anything except for cloning.这排除了使用任何形式的借用,并且因为foo()通过引用接受self ,除了克隆之外,您实际上不能做任何事情。

Also, supposedly this third_party is written without any weird unsafe hacks, so it is quite safe to assume that the Vec which is passed into it is eventually dropped and deallocated.此外,据说这个third_party是在没有任何奇怪的不安全黑客的情况下编写的,因此可以很安全地假设传入它的Vec最终被丢弃和释放。 Therefore, unsafely creating a copy of the original Vec without cloning it (by copying internal pointers) is out of question - you'll definitely get a use-after-free if you do it.因此,不安全地创建原始Vec的副本而不克隆它(通过复制内部指针)是不可能的 - 如果你这样做,你肯定会得到一个 use-after-free。

While your question does not state it, the fact that you want to preserve the original value of data is kind of a natural assumption.虽然您的问题没有说明,但您想要保留data的原始价值这一事实是一种自然的假设。 If this assumption can be relaxed, and you're actually okay with giving the data instance out and eg replacing it with an empty vector internally, then there are several things you can potentially do:如果这个假设可以放宽,并且您实际上可以提供data实例并在内部用空向量替换它,那么您可以做几件事:

  1. Switch foo(&self) to foo(&mut self) , then you can quite easily extract data and replace it with an empty vector.foo(&self)切换到foo(&mut self) ,然后您可以非常轻松地提取data并将其替换为空向量。
  2. Use Cell or RefCell to store the data.使用CellRefCell来存储数据。 This way, you can continue to use foo(&self) , at the cost of some runtime checks when you extract the value out of a cell and replace it with some default value.这样,您可以继续使用foo(&self) ,代价是当您从单元格中提取值并将其替换为某个默认值时进行一些运行时检查。

Both these approaches, however, will result in you losing the original Vec .但是,这两种方法都会导致您丢失原始Vec With the given third-party API there is no way around that.使用给定的第三方 API 没有办法解决这个问题。

If you still can somehow influence this external API, then the best solution would be to change it to accept &[i32] , which can easily be obtained from Vec<i32> with borrowing.如果您仍然可以以某种方式影响这个外部 API,那么最好的解决方案是将其更改为接受&[i32] ,这可以通过借用轻松从Vec<i32>获得。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM