fn 在特征中采用 FnMut 闭包 -> "patterns aren't allowed in functions without bodies" 或 "please add mut"

fn taking FnMut closure in trait -> either "patterns aren't allowed in functions without bodies" or "please add mut"

pub struct A {}

pub trait FooTakesFnMut {
    fn foo<VF>(&self, mut fnmuti32: VF)
    where
        VF: FnMut(i32);
}

impl FooTakesFnMut for A {
    fn foo<VF>(&self, mut fnmuti32: VF)
    where
        VF: FnMut(i32),
    {
        for x in 1..5 {
            fnmuti32(x);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_00() {
        let a = A;
        let mut v = Vec::new();
        let bar = |x| { v.push(x); };
        a.foo(bar);
        assert_eq!(v, vec![1,2,3,4]);
    }
}  

link to play rust playground copy

编译器抱怨:

error: patterns aren't allowed in functions without bodies
 --> src/lib.rs:9:23
  |
9 |     fn foo<VF>(&self, mut fnmuti32: VF)
  |                       ^^^^^^^^^^^^ help: remove `mut` from the parameter: `fnmuti32`
<--cut-->

但是在从 foo 函数签名中删除 mut 之后,它建议添加它们:

   Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow `fnmuti32` as mutable, as it is not declared as mutable
  --> src/lib.rs:20:13
   |
15 |     fn foo<VF>(&self,  fnmuti32: VF)
   |                        -------- help: consider changing this to be mutable: `mut fnmuti32`
...
20 |             fnmuti32(x);
   |             ^^^^^^^^ cannot borrow as mutable
<--cut-->

问题是您在特征定义中指定了 mutmut 使变量绑定可变,这种信息属于特征实现,而不是声明。

如果您删除特征定义中的 mut,您的代码将编译。

您的代码中存在一些错误,这应该有效:

pub struct A;

pub trait FooTakesFnMut {
    fn foo<VF>(&self, fnmuti32: VF)
    where
        VF: FnMut(i32);
}

impl FooTakesFnMut for A {
    fn foo<VF>(&self, mut fnmuti32: VF)
    where
        VF: FnMut(i32),
    {
        for x in 1..=5 {
            fnmuti32(x);
        }
    }
}

#[cfg(test)]
#[allow(unused_imports)]
mod tests {
    use super::*;
    
    #[test]
    fn test_00() {
        let a = A;
        let mut v = Vec::new();
        let bar = |x| { v.push(x); };
        a.foo(bar);
        assert_eq!(v, vec![1,2,3,4,5]);
    }
}    
  1. struct A {} 替换为 struct A; 以便 A 可以用作 ZST A 的唯一实例值而不是 A {}.

  2. 参数附加的mut关键字只是实现的问题,因为只要所有权转移到函数中,实现是否会发生变异参数不再由调用者决定。

  3. 1..5 更改为 1..=5 以便结果与提供的测试用例匹配。