首页 > 解决方案 > 生命周期和实现克隆的问题

问题描述

我正在尝试定义一个表示可以使用不同算术运算组合的函数的结构(仅实现了加法)。

我想Clone为我的结构实现,但是我似乎无法工作:

use std::ops::Add;
use std::boxed::Box;
use std::clone::Clone;

type InputT = i32;
type OutputT = f64;

pub struct ComposableFn<'a> {
    f: Box<dyn 'a + Fn(InputT) -> OutputT>,
}

impl<'a> ComposableFn<'a> {
    pub fn new<F: 'a + Fn(InputT) -> OutputT>(f: F) -> Self {
        Self {
            f: Box::new(f)
        }
    }

    pub fn compute(&self, x: InputT) -> OutputT {
        (self.f)(x)
    }
}

impl<'a> Add<&'a ComposableFn<'a>> for &'a ComposableFn<'a> {
    type Output = ComposableFn<'a>;
    
    fn add(self, rhs: &'a ComposableFn) -> Self::Output {
        ComposableFn::new(move |x| self.compute(x) + rhs.compute(x))
    }
}

impl<'a> Clone for ComposableFn<'a> {
    fn clone(&'a self) -> Self {
        ComposableFn::new(move |x| self.compute(x))
    }
}

fn main() {
    let id = ComposableFn::new(|x| x.into());
    println!("{}", id.compute(12));
    
    let double = &id + &id;
    println!("{}", double.compute(7));
    
    let triple = &double + &id;
    println!("{}", triple.compute(3));
}

编译时出现以下错误:

error[E0308]: method not compatible with trait
  --> src/main.rs:33:5
   |
33 |     fn clone(&'a self) -> Self {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected fn pointer `fn(&ComposableFn<'a>) -> ComposableFn<'_>`
              found fn pointer `fn(&'a ComposableFn<'a>) -> ComposableFn<'_>`
note: the anonymous lifetime #1 defined on the method body at 33:5...
  --> src/main.rs:33:5
   |
33 |     fn clone(&'a self) -> Self {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 32:6
  --> src/main.rs:32:6
   |
32 | impl<'a> Clone for ComposableFn<'a> {
   |      ^^

error: aborting due to previous error

删除'afromfn clone(&'a self)会导致以下错误:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:34:27
   |
34 |         ComposableFn::new(move |x| self.compute(x))
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 33:5...
  --> src/main.rs:33:5
   |
33 |     fn clone(&self) -> Self {
   |     ^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the types are compatible
  --> src/main.rs:34:27
   |
34 |         ComposableFn::new(move |x| self.compute(x))
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected `&ComposableFn<'_>`
              found `&ComposableFn<'a>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 32:6...
  --> src/main.rs:32:6
   |
32 | impl<'a> Clone for ComposableFn<'a> {
   |      ^^
note: ...so that the expression is assignable
  --> src/main.rs:34:9
   |
34 |         ComposableFn::new(move |x| self.compute(x))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected `ComposableFn<'a>`
              found `ComposableFn<'_>`

error: aborting due to previous error

有没有办法解决这个问题?

标签: rustlifetime

解决方案


您不能Clone以这种方式实施。Clone要求返回类型完全匹配,这意味着完全相同的生命周期'a。但是您正在尝试创建一个引用self具有不同生命周期的克隆。

直接的解决方案是克隆f。不幸的是,您不能克隆 a Box<dyn...>,至少在没有帮助的情况下不能。请参阅:如何克隆存储盒装特征对象的结构?

唯一直接的解决方案是交换BoxRc以便他们共享所有权:

use std::rc::Rc;

pub struct ComposableFn<'a> {
    f: Rc<dyn 'a + Fn(InputT) -> OutputT>,
}

impl Clone for ComposableFn<'_> {
    fn clone(&self) -> Self {
        ComposableFn { f: self.f.clone() }
    }
}

推荐阅读