Get a error when pass closure, use Arc Mutex


#1

Code:

let num = Box::new(1);
let my_cl = move || {
    let mut x = 0;
    x += *num;
    println!("the x is {}.", x);
};
let my_box_job = Box::new(my_cl);
let my_box_arc = Arc::new(Mutex::new(my_box_job)); 
{
    let my_box_arc = my_box_arc.clone();
    let my_box = my_box_arc.lock().unwrap();
    (*my_box)();
}

The error

error: cannot move out of borrowed content

Why?


#2

Works for me in the playground (link). Outputs “the x is 1.”. Can you provide a complete failing example?


#3
use std::sync::{Arc, Mutex};

fn main() {
    let num = Box::new(1);
    let my_cl = move || {
        let mut x = 0;
        x += *num;
        println!("the x is {}.", x);
    };
    let my_box_job = Box::new(my_cl);
    let my_box_arc = Arc::new(Mutex::new(my_box_job)); 
    {
        let my_box_arc = my_box_arc.clone();
        let my_box = my_box_arc.lock().unwrap();
        (*my_box)();
    }
}

This compiles and outputs “the x is 1.” on both stable and nightly.


#4

It works, my fault. original code is this:

use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex};
use std::thread;

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

fn execute<F>(job: F) where F : FnOnce() + Send + 'static
{
   let my_box_job = Box::new(job);
   let my_box_arc = Arc::new(Mutex::new(my_box_job));
   {
       let my_box_arc = my_box_arc.clone();
       let my_box = my_box_arc.lock().unwrap();
       (*my_box)();
   }
}

fn main() {
    let num = Box::new(1);
    let my_cl = move || {
        let mut x = 0;
        x += *num;
        println!("the x is {}.", x);
    };
    execute(my_cl);
}

Only a little difference, I can’t find out why…


#5

What you’re trying to do is not possible in user-level Rust code, which is why it’s being added to the compiler (if you use the nightlies they have FnBox in the standard library). There’s a workaround using “Option” if you don’t mind wasting one word: playpen.


#6

Because F is FnOnce, which means in order to call it, you have to take ownership of the closure. But you can’t take ownership of something through a pointer like that.

Given that it’s FnOnce, I’m not sure why you even need Arc and Mutex; you can’t meaningfully share a call-once closure, anyway. If you have some other reason not evident in the example, you can use Option<Box<F>>; that will allow you to .take() the closure from the Option, leaving None in its place.


#7

I’am confused…
Is a closure implements FnOnce and Send?
if not, why can I pass my_cl to execute?
if it is, why

use std::sync::{Arc, Mutex};

fn main() {
    let num = Box::new(1);
    let my_cl = move || {
        let mut x = 0;
        x += *num;
        println!("the x is {}.", x);
    };
    let my_box_job = Box::new(my_cl);
    let my_box_arc = Arc::new(Mutex::new(my_box_job)); 
    {
        let my_box_arc = my_box_arc.clone();
        let my_box = my_box_arc.lock().unwrap();
        (*my_box)();
    }
}

just works…

Have I missed something important?


#8

All closures implement FnOnce. Some closures also implement FnMut and Fn. Your last code example doesn’t destroy my_box, so it only works with functions that can validly be called multiple times.

Using the * operator on a Box gives you a borrowed value, (it’s calling either deref or deref_mut behind the scenes); you call call a Fn or a FnMut through a borrow, but calling a FnOnce requires an owned value.

You can use FnOnce with boxes, but only if those boxes have statically known size. The dynamically-sized version of FnOnce is called FnBox, and I recommend switching to nightly and using FnBox rather than trying to implement it yourself.


#9

I’m confused more…
Why Fn extends FnMut, and FnMut extends FnOnce?

FnOnce extends FnMut, FnMut extends Fn,
is this more reasonable?

or

FnOnce extends Fn, and FnMut extends Fn.

thanks.


#10

FnMut extends (refines) FnOnce because FnOnce is the more general concept. A FnMut can be called many times through a unique reference, a FnOnce only needs to be callable once.

Fn extends FnMut because FnMut is the more general concept. A Fn can be called through any reference, a FnMut only needs to be callable through unique references.

(I’m making assumptions here that may not be justified, but the closure type system will probably make more sense if you take the time to become familiar with the ownership/borrowing system before trying to work with closures in Rust. If you do that, I think you’ll find that the separation into three classes is effectively forced by the requirements of environment handling (and note that the environment is effectively an argument, and therefore contravariant). Though the names chosen could have been different.)


#11

trait A {
}

trait B {
}

impl A for B {

}

means B is a A…

For this example…

impl FnOnce for FnMut means FnMut is a FnOnce

impl FnMut for Fn meas Fn is a FnMut

but i still think that

FnMut and FnOnce is Fn, and FnMut, FnOnce seperate the Fn to two parts…

or

FnMut and FnOnce is Fn, and FnOnce is FnMut.


#12

Actually, no, trait B: A {} means that anything that implements B must implement A, whereas impl<T: B> A for T {} means that anything that implements B automatically implements A. impl A for B, assuming both are still traits, means that A is implemented through dynamic dispatch to B, which is probably not what you mean, and is not how the Fn trio are tied together. The first two implement something closer to subtyping.

According to traditional OOP, a subtype should be usable as the base type. A FnOnce can only be called once, while a FnMut can be called any number of times. I cannot treat a FnOnce like a FnMut, because I cannot call a FnOnce multiple times while I can do that with a FnMut. The other way around is possible: I can pretend that a FnMut can only be called once. Therefore, a FnMut is a subtype of an FnOnce, because a FnMut can be substituted for a FnOnce. Fn can be treated like a FnMut because a FnMut requires exclusive access, while references to a Fn can be freely aliased, but I can safely pretend that references to a Fn cannot be aliased. The formal term for this “pretending” is downcasting from the subtype to the base type, and the requirement that downcasting adds restrictions, never removing them, is the Liskov substitution principle.


#13

I know, no, trait B: A {} means that B is A.

I mean that trait B: A {} means that B is kind of A.

Fn:FnOnce…
function(Fn) is a kind of function that only can be called once…My god…

is [Function that only can be called once is a kind of function(Fn)] more reasonable?

you know, rust-lang user design from real world…and rust-lang designer look things from the reference(or pointer), that is the difference…


#14

I want to say more…

can be called once isn’t equal to can be only called once, it’s absolutely different.


#15

Fn:FnOnce…
function(Fn) is a kind of function that only can be called once…My god…

That’s, I admit, a stupid naming mistake on the Rust devs’ part. Fn is not the trait of all functions; Fn is the trait of all functions that can be called using a shared reference.


#16

That is actually the critical observation here. FnOnce only means “can be called once”. There is no requirement that something implementing FnOnce can not be called multiple times. Due to the implementation details any type that is FnOnce + Copy can be called multiple times as FnOnce. For all types T that are Fn or FnMut, &(mut) T is FnOnce, the type can be called once using the respective borrow.

Similarly FnMut means “can mutate the environment”, not “mutates the environment”. Hence, any type that is Fn is also FnMut.


#17

Ignore the names of three traits, let’s see the implementation.
The only difference between the three traits is

&mut self(FnMut), &self(Fn), self(FnOnce)…

&self means &(un-mut) self,
isn’t borrow consist of mut and un-mut?

then, self, move the binding…

Is there any common concept of the three types?

Thanks you all for helping me.