简体   繁体   English

发送只能针对结构体/枚举类型而不是特征来实现

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

I have having difficulty implementing Send for a trait. 我很难实现Send特质。 Full code in the playground . 操场上的完整代码

I have a Storage trait : 我有一个Storage特征:

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: 它是Consistency结构的一部分:

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

I have implemented a MemoryStorage struct: 我已经实现了一个MemoryStorage结构:

#[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: 添加unsafe impl Send for Storage {}会给我带来一个矛盾的错误,即无法针对特征实施Send

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. 您对实现trait的对象trait对象 )进行了引用,但是不能保证您的trait能够在线程之间发送。

You need to ensure that it is. 您需要确保它是。 You can require all implementors of your trait are Send : 您可以要求特征的所有实现者均为Send

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

Or that this specific trait object implements Send : 或者该特定特征对象实现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 . 您很多人需要返回并重新阅读Rust编程语言 ,尤其是有关并发性章节

See also: 也可以看看:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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