简体   繁体   中英

Send can only be implemented for a struct/enum type, not a trait

I have having difficulty implementing Send for a trait. Full code in the playground .

I have a Storage trait :

pub trait Storage {
    fn get_value(&self, key: &str) -> Result<Vec<u8>, Error>;
    fn put_value(&mut self, key: &str, value: &[u8]) -> Result<(), Error>;
    fn key_exists(&self, key: &str) -> bool;
    fn delete_key(&mut self, key: &str) -> Result<(), Error>;
}

It is part of the Consistency struct:

pub struct Consistency<'a> {
    storage: &'a mut Storage,
}

I have implemented a MemoryStorage struct:

#[derive(Debug)]
struct MemoryStorage {
    data: HashMap<String, Vec<u8>>,
}

impl Storage for MemoryStorage {
    fn get_value(&self, key: &str) -> Result<Vec<u8>, Error> {
        self.data.get(key).map_or(
            Err(Error::new(ErrorKind::NotFound, "Key does not exists")),
            |v| Ok(v.clone()),
        )
    }

    fn put_value(&mut self, key: &str, value: &[u8]) -> Result<(), Error> {
        self.data.insert(key.to_string(), Vec::from(value));
        Ok(())
    }

    fn key_exists(&self, key: &str) -> bool {
        self.data.contains_key(key)
    }

    fn delete_key(&mut self, key: &str) -> Result<(), Error> {
        self.data.remove(key).map_or(
            Err(Error::new(ErrorKind::NotFound, "Key does not exists")),
            |v| Ok(()),
        )
    }
}

I wrote a test:

#[test]
fn multiple_threads_bombing_storage() {
    const parallels: usize = 10;
    let mut storage = MemoryStorage {
        data: HashMap::new(),
    };
    let mut consistency = Consistency::new(&mut storage);

    // create all keys.
    let mut keys = Vec::<String>::new();
    for k in 1..parallels {
        keys.push(k.to_string());
    }

    let zero = "0".as_bytes();
    // put default values in files.
    for key in keys.clone() {
        consistency.put_value(&key, zero).unwrap();
    }

    // test write threads
    let write_thread = |to_write: Vec<u8>, keys: &mut Vec<String>| {
        let mut rng = rand::thread_rng();
        rng.shuffle(keys);

        for key in keys {
            let mut val = consistency.get_value(key).unwrap();
            val.append(to_write.clone().as_mut());
            consistency.put_value(key, &val).unwrap();
        }
    };

    // start parallels threads..
    for t in 1..parallels {
        let handle = thread::spawn(move || {
            write_thread(t.to_string().into_bytes(), &mut keys);
        });
    }

    // wait for all threads..

    // check if all parallels keys have all numbers in any order.
}

This gives me an error:

error[E0277]: the trait bound `fileapi::Storage: std::marker::Send` is not satisfied
   --> src/consistency.rs:158:26
    |
158 |             let handle = thread::spawn(move || {
    |                          ^^^^^^^^^^^^^ `fileapi::Storage` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `fileapi::Storage`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut fileapi::Storage`
    = note: required because it appears within the type `consistency::Consistency<'_>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut consistency::Consistency<'_>`
    = note: required because it appears within the type `[closure@src/consistency.rs:145:28: 154:10 consistency:&mut consistency::Consistency<'_>]`
    = note: required because it appears within the type `[closure@src/consistency.rs:158:40: 160:14 write_thread:[closure@src/consistency.rs:145:28: 154:10 consistency:&mut consistency::Consistency<'_>], t:usize, keys:std::vec::Vec<std::string::String>]`
    = note: required by `std::thread::spawn`

Adding unsafe impl Send for Storage {} gives me a contradictory error that Send can't be implemented for a trait:

cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `fileapi::Storage + 'static`

I don't understand how to solve this problem.

You have a reference to something implementing a trait (a trait object ), but your trait isn't guaranteed to be able to be sent between threads.

You need to ensure that it is. You can require all implementors of your trait are Send :

pub trait Storage: Send {
    // ...
}

Or that this specific trait object implements Send :

pub struct Consistency<'a> {
    storage: &'a mut (Storage + Send),
}

Your code has many other issues, so it still doesn't compile. Among them:

  1. You attempt to pass a stack-allocated variable to a thread.
  2. You try to share a mutable reference among multiple threads.

You many need to go back and re-read The Rust Programming Language , especially the chapter on concurrency .

See also:

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