English 中文(简体)
Rust compiler does not unify types that both `impl Future<Output=()>` in branches of `if let` expression
原标题:

While trying to create a Future conditionally, for later use with select_biased!:

            let mut heartbeat_timer = if let ServerState::Leader(_, _, _) = server_state {
                // if we re the Leader, we want to send out AppendEntries RPC at a
                // minimum interval as required to maintain our leadership
                task::sleep(HEARTBEAT_DURATION)
            } else {
                // if we re not the leader, no need to send those
                pending::<()>()
            };

// ...

            select_biased! {
                h = heartbeat_timer => self.heartbeat().await,
                // ... some others declared in priority order
                default => task::yield_now().await,
            }

I am having difficulty understanding why I get a compilation error:

error[E0308]: `if` and `else` have incompatible types
   --> src/raft.rs:185:17
    |
182 |               let heartbeat_timer = if let ServerState::Leader(_, _, _) = server_state {
    |  ___________________________________-
183 | |                 task::sleep(HEARTBEAT_DURATION)
    | |                 ------------------------------- expected because of this
184 | |             } else {
185 | |                 pending::<()>()
    | |                 ^^^^^^^^^^^^^^^ expected future, found `Pending<()>`
186 | |             };
    | |_____________- `if` and `else` have incompatible types
    |
    = note: expected opaque type `impl futures::Future<Output = ()>`
                    found struct `futures::future::Pending<()>`

Clicking (in my IDE) through pending shows me that its type is Pending<T>, and I can further see that Pending<T> implements Future<Output=T>:

impl<T> Future for Pending<T> {
    type Output = T;

    fn poll(self: Pin<&mut Self>, _: &mut Context< _>) -> Poll<T> {
        Poll::Pending
    }
}

For some reason I can t yet understand, the compiler fails to follow the same breadcrumbs. What secret does the compiler know that am I missing? Is there some straightforward transformation of my code that would satisfy the compiler? What should I be thinking that would have led me to supply what the compiler needs?

rustup --version includes the output:

info: The currently active `rustc` version is `rustc 1.69.0 (84c898d65 2023-04-16)`
问题回答

impl return types don t work that way, unfortunately. They aren t dynamic dispatch; an impl return type must still be a single concrete type; it s just that you don t have to specify the type in your code. If you have two (or more) branch arms that return different types, then the impl return will reject it. If you want to do that, you have to use full dynamic dispatch. That means a dyn trait object and a Box or other indirection mechanism.

In your case, I might recommend replacing impl Future<Output=()> with Box<dyn Future<Output=()>>. On each of the branches, you ll have to do an explicit Box::new around the desired return value to add the layer of indirection.





相关问题
Creating an alias for a variable

I have the following code in Rust (which will not compile but illustrates what I am after). For readability purposes, I would like to refer the same string with two different names so that the name of ...

Rust Visual Studio Code code completion not working

I m trying to learn Rust and installed the Rust extension for VSCode. But I m not seeing auto-completions for any syntax. I d like to call .trim() on String but I get no completion for it. I read that ...

热门标签