英文:
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<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 argument
答案1
得分: 1
因为 Clone
不是 对象安全(它会返回实际类型,而不是 Box<dyn Clone>
),所以你需要一个解决方法。你可以几乎使用来自 这个问题 的方法,只是因为你不拥有 Iterator
trait,你需要创建一个新的 trait。(playground)
trait ClonableIterator: Iterator {
fn clone_box(&self) -> Box<dyn ClonableIterator<Item = Self::Item>>;
}
impl<T, I> ClonableIterator for T
where
T: Iterator<Item = I> + Clone + 'static,
{
fn clone_box(&self) -> Box<dyn ClonableIterator<Item = I>> {
Box::new(self.clone())
}
}
然后你可以在你的结构体中存储这个 trait 对象。
counter: Box<dyn ClonableIterator<Item = usize>>
并且你可以使用 clone_box
为你的结构体实现 Clone
。
impl<F> Clone for EquationIterator<F> {
fn clone(&self) -> Self {
EquationIterator {
counter: self.counter.clone_box(),
formula: self.formula.clone(),
}
}
}
你还可以对 Fn
trait 进行类似的操作,我已经将它升级为 FnMut
,因为它现在是独占的。
trait ClonableFnMut<T, O>: FnMut(T) -> O {
fn clone_box(&self) -> Box<dyn ClonableFnMut<T, O>>;
}
impl<F, T, O> ClonableFnMut<T, O> for F
where
F: FnMut(T) -> O + Clone + 'static,
{
fn clone_box(&self) -> Box<dyn ClonableFnMut<T, O>> {
Box::new(self.clone())
}
}
然后你可以将它添加到结构体中。
formula: Box<dyn ClonableFnMut<usize, F>>
并修改你的 Clone
实现。
formula: self.formula.clone_box()
我无法完全让它与 dyn-clone 配合使用,但可能有一种方法。
请注意,你仍然需要手动实现 Clone
,因为自动生成的实现会有条件地要求 F
是 Clone
,这并不是必要的。
英文:
Because Clone
isn't object-safe (it would return the actual type, not Box<dyn Clone>
), 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(&self) -> Box<dyn ClonableIterator<Item = Self::Item>>;
}
impl<T, I> ClonableIterator for T
where
T: Iterator<Item = I> + Clone + 'static,
{
fn clone_box(&self) -> Box<dyn ClonableIterator<Item = I>> {
Box::new(self.clone())
}
}
Then you can store a trait object of this trait in your struct.
counter: Box<dyn ClonableIterator<Item = usize>>
And you can implement Clone
for your struct using clone_box
.
impl<F> Clone for EquationIterator<F> {
fn clone(&self) -> 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<T, O>: FnMut(T) -> O {
fn clone_box(&self) -> Box<dyn ClonableFnMut<T, O>>;
}
impl<F, T, O> ClonableFnMut<T, O> for F
where
F: FnMut(T) -> O + Clone + 'static,
{
fn clone_box(&self) -> Box<dyn ClonableFnMut<T, O>> {
Box::new(self.clone())
}
}
And then you can add it to the struct.
formula: Box<dyn ClonableFnMut<usize, F>>
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<F, I: Iterator<Item = usize> + Clone> {
counter: Box<I>,
formula: Arc<dyn Fn(usize) -> F>,
}
fn main() {
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论