简体   繁体   中英

std::sync::Arc of trait in Rust

I am trying to implement library for making TCP servers.

This is very simplified code with a problem:

#![crate_name="http_server2"]
#![crate_type="lib"]

use std::io::{TcpListener, Listener, Acceptor, TcpStream, IoResult, Reader, Writer};
use std::ops::Fn;
use std::sync::Arc;


pub trait Handler: Sized + Send {
    fn do_it(s: TcpStream) -> IoResult<()>;
}

fn serve(handler: Arc<Handler + Sized>) -> IoResult<()>
{
    let listener = TcpListener::bind("127.0.0.1", 1234);

    for stream in try!(listener.listen()).incoming() {
        let stream = try!(stream);
        let handler = handler.clone();
        spawn(proc() {
            handler.do_it(stream);
        });
    }
    Ok(())
}

Compiler totally ignores my specifications of Handler + Sized . If I implement structure with trait Handler and try to call serve with this structure, such advice about size will be ignored too ( http://is.gd/OWs22i ).

<anon>:13:1: 25:2 error: the trait `core::kinds::Sized` is not implemented for the type `Handler+'static+Sized`
<anon>:13 fn serve(handler: Arc<Handler + Sized>) -> IoResult<()>
<anon>:14 {
<anon>:15     let listener = TcpListener::bind("127.0.0.1", 1234);
<anon>:16 
<anon>:17     for stream in try!(listener.listen()).incoming() {
<anon>:18         let stream = try!(stream);
          ...
<anon>:13:1: 25:2 note: the trait `core::kinds::Sized` must be implemented because it is required by `alloc::arc::Arc`
<anon>:13 fn serve(handler: Arc<Handler + Sized>) -> IoResult<()>
<anon>:14 {
<anon>:15     let listener = TcpListener::bind("127.0.0.1", 1234);
<anon>:16 
<anon>:17     for stream in try!(listener.listen()).incoming() {
<anon>:18         let stream = try!(stream);
          ...
error: aborting due to previous error

How can I implement one template function with multithreading that will accept different handlers?

As I said in my comment above,

use std::io::{TcpListener, Listener, Acceptor, TcpStream, IoResult, Writer};
use std::sync::Arc;

pub trait Handler: Sized + Send {
    fn do_it(&self, s: TcpStream) -> IoResult<()>;
}

fn serve<T: Handler + Sized + Send + Sync>(handler: Arc<T>) -> IoResult<()> {
    let listener = TcpListener::bind("127.0.0.1", 1234);
    for stream in try!(listener.listen()).incoming() {
        let stream = try!(stream);
        let handler = handler.clone();
        spawn(proc() { 
            let _ = handler.do_it(stream); 
        });
    }
    Ok(())
}

struct Hello {
    x: u32,
}

impl Handler for Hello {
    fn do_it(&self, mut s: TcpStream) -> IoResult<()> { s.write_le_u32(self.x) }
}

fn main() { 
    let s = Arc::new(Hello{x: 123,}); 
    let _ = serve(s); 
}

compiles fine. (playpen)


Changes

  1. Make do_it take &self .
  2. Make serve generic, by adding a type parameter with the constraints you want.
  3. Make the impl of Handler for Hello in do_it not discard the result of the write (remove ; ).
  4. Clarify with let _ = ... that we intentionally discard a result.

You will not be able to execute it in the playpen though ( application terminated abnormally with signal 31 (Bad system call) ), as the playpen forbids IO (network IO in this case). It runs fine on my local box though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM