Why `&mut self` works instead of `&self` in below async code

use async_trait::async_trait;
use tokio::{self, spawn};

#[async_trait]
pub trait Consumer {
    async fn consume(&self);
}

pub struct DefaultConsumer;

#[async_trait]
impl Consumer for DefaultConsumer {
    async fn consume(&self) {
        println!("hello consumer!");
    }
}
struct Test {
    inner: Box<dyn Consumer + Send>,
}

impl Test {
    async fn run(mut self) {
        let f = self.level1();
        f.await;
    }
    async fn level1(&mut self) {
        let f = self.level2();
        f.await;

    }
    async fn level2(&self) { // OK if change to `&mut self`
    }
}

#[tokio::main]
async fn main() {
    let mut t = Test {
        inner: Box::new(DefaultConsumer),
    };
    spawn(async move {
        let f = t.run();
        f.await;
    });
}

Is the question essentially "why can we call &self method on &mut self"?

Why wouldn't it work? What did you expect instead?

1 Like

Because Test is not Sync. And for some T which is !Sync, &T is !Send but &mut T is Send.

With sending &T to another thread, since &T is Copy as well, you can effectively access T from two different thread at the same time, with violates T: !Sync. But you cannot copy &mut T, which is unique, so it doesn't violate T: !Sync.

2 Likes