如何在Rust中实现包含动态迭代器的结构体的克隆?

huangapple go评论119阅读模式
英文:

How to implement Clone on a struct that contains dyn Iterator in Rust?

问题

I have the following struct in Rust:

#[derive(Clone)]
pub struct EquationIterator<F> {
    counter: Box<dyn Iterator<Item = usize>>,
    formula: Arc<dyn Fn(usize) -> Equation<F>>,
}

I had to use an Arc to wrap the closure otherwise I couldn't implement Clone on the struct. Even with this, I still cannot derive Clone because the compiler is complaining about the dyn Iterator not implementing Clone.

I've tried implementing Clone manually but no luck either. Any idea?

To add more colors, this structure is an iterator that goes through some arbitrary range (e.g. counter = [2, 5, 9]) and calls some closure with the current counter value as an argument.

You can find more details and code examples in this Rust Playground link.

英文:

I have the following struct in Rust:

#[derive(Clone)]
pub struct EquationIterator&lt;F&gt; {
    counter: Box&lt;dyn Iterator&lt;Item = usize&gt;&gt;,
    formula: Arc&lt;dyn Fn(usize) -&gt; Equation&lt;F&gt;&gt;,
}

I had to use an Arc to wrap the closure otherwise I couldn't implement Clone on the struct. Even with this, I still cannot derive Clone because the compiler is complaining about the dyn Iterator not implementing Clone.

I've tried implementing Clone manually but no luck either. Any idea?

To add more colors, this structure is an iterator that goes through some arbitrary range (e.g. counter = [2, 5, 9]) and calls some closure with the current counter value as argument

https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=9fb31441d9007d51c050bdd9e8f2d5c7

答案1

得分: 1

因为 Clone 不是 对象安全(它会返回实际类型,而不是 Box&lt;dyn Clone&gt;),所以你需要一个解决方法。你可以几乎使用来自 这个问题 的方法,只是因为你不拥有 Iterator trait,你需要创建一个新的 trait。(playground)

trait ClonableIterator: Iterator {
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableIterator&lt;Item = Self::Item&gt;&gt;;
}

impl&lt;T, I&gt; ClonableIterator for T
where
    T: Iterator&lt;Item = I&gt; + Clone + &#39;static,
{
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableIterator&lt;Item = I&gt;&gt; {
        Box::new(self.clone())
    }
}

然后你可以在你的结构体中存储这个 trait 对象。

counter: Box&lt;dyn ClonableIterator&lt;Item = usize&gt;&gt;

并且你可以使用 clone_box 为你的结构体实现 Clone

impl&lt;F&gt; Clone for EquationIterator&lt;F&gt; {
    fn clone(&amp;self) -&gt; Self {
        EquationIterator {
            counter: self.counter.clone_box(),
            formula: self.formula.clone(),
        }
    }
}

你还可以对 Fn trait 进行类似的操作,我已经将它升级为 FnMut,因为它现在是独占的。

trait ClonableFnMut&lt;T, O&gt;: FnMut(T) -&gt; O {
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableFnMut&lt;T, O&gt;&gt;;
}

impl&lt;F, T, O&gt; ClonableFnMut&lt;T, O&gt; for F
where
    F: FnMut(T) -&gt; O + Clone + &#39;static,
{
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableFnMut&lt;T, O&gt;&gt; {
        Box::new(self.clone())
    }
}

然后你可以将它添加到结构体中。

formula: Box&lt;dyn ClonableFnMut&lt;usize, F&gt;&gt;

并修改你的 Clone 实现。

formula: self.formula.clone_box()

我无法完全让它与 dyn-clone 配合使用,但可能有一种方法。

请注意,你仍然需要手动实现 Clone,因为自动生成的实现会有条件地要求 FClone,这并不是必要的。

英文:

Because Clone isn't object-safe (it would return the actual type, not Box&lt;dyn Clone&gt;), you need a workaround. You can almost use the method from this question, except because you don't own the Iterator trait, you need to make a new trait. (playground)

trait ClonableIterator: Iterator {
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableIterator&lt;Item = Self::Item&gt;&gt;;
}

impl&lt;T, I&gt; ClonableIterator for T
where
    T: Iterator&lt;Item = I&gt; + Clone + &#39;static,
{
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableIterator&lt;Item = I&gt;&gt; {
        Box::new(self.clone())
    }
}

Then you can store a trait object of this trait in your struct.

counter: Box&lt;dyn ClonableIterator&lt;Item = usize&gt;&gt;

And you can implement Clone for your struct using clone_box.

impl&lt;F&gt; Clone for EquationIterator&lt;F&gt; {
    fn clone(&amp;self) -&gt; Self {
        EquationIterator {
            counter: self.counter.clone_box(),
            formula: self.formula.clone(),
        }
    }
}

You can also do this for the Fn trait, which I've upgraded to FnMut since it is now owned exclusively.

trait ClonableFnMut&lt;T, O&gt;: FnMut(T) -&gt; O {
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableFnMut&lt;T, O&gt;&gt;;
}

impl&lt;F, T, O&gt; ClonableFnMut&lt;T, O&gt; for F
where
    F: FnMut(T) -&gt; O + Clone + &#39;static,
{
    fn clone_box(&amp;self) -&gt; Box&lt;dyn ClonableFnMut&lt;T, O&gt;&gt; {
        Box::new(self.clone())
    }
}

And then you can add it to the struct.

formula: Box&lt;dyn ClonableFnMut&lt;usize, F&gt;&gt;

And change your Clone implementation.

formula: self.formula.clone_box()

I couldn't quite get this to work with dyn-clone, but there might be a way.

Note that you would need to implement Clone manually anyway because the derive would make it conditional on F being Clone, which isn't necessary.

答案2

得分: 0

// 有可能 `Iterator` 的实现者不可克隆。你需要告诉编译器只允许实现了 `Clone` 和 `Iterator` 的类型。
use std::sync::Arc;

#[derive(Clone)]
pub struct EquationIterator<F, I: Iterator<Item = usize> + Clone> {
    counter: Box<I>,
    formula: Arc<dyn Fn(usize) -> F>,
}

fn main() {

}
英文:

It is possible that an implementor of Iterator is not clonable. You need to specify to the compiler that only types that implement Clone and Interator are allowed.

use std::sync::Arc;

#[derive(Clone)]
pub struct EquationIterator&lt;F, I: Iterator&lt;Item = usize&gt; + Clone&gt; {
    counter: Box&lt;I&gt;,
    formula: Arc&lt;dyn Fn(usize) -&gt; F&gt;,
}

fn main() {

}

https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=9fb31441d9007d51c050bdd9e8f2d5c7

huangapple
  • 本文由 发表于 2023年6月6日 07:59:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410657.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定