-1
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

Compiler complains:

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-->

but after removing mut from foo functions signatures , it suggests adding them :

   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-->
Grzegorz Wierzowiecki
  • 10,545
  • 9
  • 50
  • 88
  • Does this answer your question? [What's the difference between placing "mut" before a variable name and after the ":"?](https://stackoverflow.com/questions/28587698/whats-the-difference-between-placing-mut-before-a-variable-name-and-after-the) – E_net4 May 25 '21 at 08:43
  • Not at all, because in my case the issue of semantic difference between `trait` and implementation `impl`. And https://stackoverflow.com/a/67684589/544721 captured exactly problem in his point no .2 ,that's why I edited his answer to highlight answer no.2. – Grzegorz Wierzowiecki May 31 '21 at 16:40

2 Answers2

1

The problem is that you specified the mut in the trait definition. The mut makes the variable binding mutable, this kind of information belongs in the trait implementation, not the declaration.

If you remove the mut on your trait definition, your code compiles.

sebpuetz
  • 2,430
  • 1
  • 7
  • 15
0

There are some mistakes in your code and this should work:

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 {} is replaced with struct A; so that A could be used as the only instance value of the ZST A instead of A {}.

  2. The mut keyword attached to a parameter is only a matter of an implementation because as long as the ownership is transferred into the function, whether the implementation would mutate the argument is no longer decided by the caller.

  3. 1..5 is changed to 1..=5 so that the result would match the provided test case.

Grzegorz Wierzowiecki
  • 10,545
  • 9
  • 50
  • 88
Alsein
  • 4,268
  • 1
  • 15
  • 35
  • Please provide a citation for your point 1. `struct A {}` and `struct A` are both zero sized. – Shepmaster May 25 '21 at 13:47
  • @Shepmaster I didn't mean that `struct A {}` is not zero sized. But there are ways to define a ZST. As a value is instantiate with `A`, the definition has to be `struct A;` so that it could compile. – Alsein May 26 '21 at 06:46