4

I don't know why this code is not ok

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

struct Worker;

impl Worker {
    fn new<T: FnOnce() + Send + 'static>(receiver: Arc<Mutex<Receiver<Box<T>>>>) -> Worker {
        Worker
    }
}

fn main() {
    let (tx, rx) = mpsc::channel();
    let rx: Arc<Mutex<Receiver<Box<FnOnce() + Send + 'static>>>> = Arc::new(Mutex::new(rx));
    Worker::new(rx);
}

The compiler told me

error[E0277]: the trait bound `std::ops::FnOnce() + std::marker::Send + 'static: std::marker::Sized` is not satisfied
  --> src/main.rs:16:5
   |
16 |     Worker::new(rx);
   |     ^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::ops::FnOnce() + std::marker::Send + 'static`
   |
   = note: `std::ops::FnOnce() + std::marker::Send + 'static` does not have a constant size known at compile-time
   = note: required by `Worker::new`

but when I use type alias like this, compilation is passed. Can anyone tell me the reason? I'm very confused ... In my opinion, the two methods is same, the type alias "Job" is just a shorten method.

use std::thread::JoinHandle;
use std::thread;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::{Arc, Mutex};
struct Worker;

type Job = Box<FnOnce() + Send + 'static>;

impl Worker {
    fn new(receiver: Arc<Mutex<Receiver<Job>>>)->Worker {
        Worker
    }
}

fn main(){
   let (tx, rx) = mpsc::channel();
   let rx = Arc::new(Mutex::new(rx));
   Worker::new(rx);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Frio
  • 160
  • 1
  • 7
  • Just to clarify the vote: `T` is implicitly `Sized` in `Box where T: FnOnce() + Send + 'static`, yet the first version attempts to call `Worker::new` where `T = (FnOnce() + Send + 'static)`, which is not sized. Just add `?Sized` to the constraint and it will compile: http://play.integer32.com/?gist=cbaff0acd0eb5842ef77da5d0201df33&version=stable – E_net4 Jul 17 '17 at 15:57
  • Thanks for you response! I want to know a little more, why in type alias version, I don't need to add the ?Sized trait? – Frio Jul 17 '17 at 16:04
  • That's because you don't have a type parameter in the second version at all. Had you declared `Job` like `type Job = Box;`, you would have had the same problem. – E_net4 Jul 17 '17 at 16:06
  • There's additional problem. It will compile, but it will not work. `Box` is unusable yet. `Box` should be used instead. – red75prime Jul 17 '17 at 16:09
  • oh, I see.Can you tell me when should I add ?Sized? Feel like ?Size doesn't make any sense, Why compiler don't add ?Size automatically for me? – Frio Jul 17 '17 at 16:11
  • @Frio, in this case you don't really need `?Sized` or generic `new()`. I'll try to add answer a bit later. – red75prime Jul 17 '17 at 16:27
  • I feel this was closed a bit prematurely, as the primary issue of the question in the title does not have to do with `Sized`, but the difference between trait objects and types that implements traits (i.e. ` Box` vs `Box`). Probably an answer for that somewhere as well, just have not found a one that matches this question well yet. – Erik Vesteraas Jul 17 '17 at 16:35
  • It seems I will not. Anyway, every closure, you seem to intend to pass into `Worker`, has unique type. Thus you will be able to pass exactly one closure into it. Other closures will have incompatible types. You'll need to use trait object `Box`, that is what you do in second version of your code. – red75prime Jul 17 '17 at 16:38
  • @E_net4, please, consider removal of duplicate status. – red75prime Jul 17 '17 at 16:41
  • 1
    @red75prime I do not have such a privilege, the OP has accepted the duplicate and it can only be retracted by voting to reopen or directly done so by a gold badge holder. Besides, it's not reasonable to reopen now without the question covering that concern, which was recently discovered. If the question is rephrased to ask about that problem in particular, then it's fair to reconsider. – E_net4 Jul 17 '17 at 16:54
  • @red75prime Why I have to use Fn()? The closure I want to pass is a task which would be processed only once.Is't it more suitable with FnOnce()? – Frio Jul 17 '17 at 16:58
  • @Frio, `Box` doesn't work yet, you get compilation error if you call it. [Issue #28796](https://github.com/rust-lang/rust/issues/28796) – red75prime Jul 17 '17 at 17:02
  • I couldn't really find a good question/answer to link to. So I wrote a new one here: https://stackoverflow.com/questions/45151770/what-is-the-difference-between-t-trait-boxt-and-boxtrait-in-rust/45151772#45151772 – Erik Vesteraas Jul 17 '17 at 19:03
  • @ErikVesteraas Your new question/answers has resovled all my question now.thanks! – Frio Jul 18 '17 at 00:58

0 Answers0