Ограничение черты `(): futures::Future` не выполняется при использовании TcpConnectionNew

Я пытаюсь написать простой TCP-клиент в Rust, используя Tokio crate. Мой код довольно близок к этому примеру, за исключением TLS:

extern crate futures;
extern crate tokio_core;
extern crate tokio_io;

use futures::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_io::io;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let connection = TcpStream::connect(&"127.0.0.1:8080".parse().unwrap(), &handle);

    let server = connection.and_then(|stream| {
        io::write_all(stream, b"hello");
    });

    core.run(server).unwrap();
}

Однако компиляция завершается с ошибкой:

error[E0277]: the trait bound `(): futures::Future` is not satisfied
  --> src/main.rs:16:29
   |
16 |     let server = connection.and_then(|stream| {
   |                             ^^^^^^^^ the trait `futures::Future` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `futures::IntoFuture` for `()`

error[E0277]: the trait bound `(): futures::Future` is not satisfied
  --> src/main.rs:20:10
   |
20 |     core.run(server).unwrap();
   |          ^^^ the trait `futures::Future` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `futures::IntoFuture` for `()`

Я нахожу это странным, потому что согласно документации это должно быть реализовано.

я использую

  • Ржавчина 1.19.0
  • фьючерсы 0.1.16
  • Токио-ядро 0.1.10
  • Токио-ио 0.1.3

Что мне не хватает?

2 ответа

Решение

TL;DR: удалить точку с запятой после io::write_all,


Просмотрите определение and_then:

fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F> 
where
    F: FnOnce(Self::Item) -> B,
    B: IntoFuture<Error = Self::Error>,
    Self: Sized, 

Закрытие (F) должен вернуть какой-то тип (B) которые можно превратить в будущее (B: IntoFuture) с типом ошибки, который соответствует начальному закрытию (Error = Self::Error).

Что возвращает ваше закрытие? (), Это почему? Потому что вы поставили точку с запятой (;) в конце вашей строки. () не реализует черту IntoFuture, что указывается в части сообщения об ошибке "в значении futures::IntoFuture за () ":

impl<F: Future> IntoFuture for F {
    type Future = F;
    type Item = F::Item;
    type Error = F::Error;
}

Удаление точки с запятой приведет к Future вернулся io::write_all быть возвращенным обратно and_then и программа скомпилируется.

В целом, фьючерсы работают путем объединения меньших компонентов, которые сами являются фьючерсами. Все это работает вместе, чтобы построить одно большое будущее, которое по сути является конечным автоматом. Это хорошо иметь в виду, так как вам почти всегда нужно возвращать будущее при использовании таких комбинаторов.

К сожалению, ответ здесь довольно конкретный, но возникает вопрос для любого вида поиска:

черта futures::Future не реализовано для ()

Типичный сценарий такого рода ошибок:

foo.then(|stream| {
    // ... Do random things here
    final_statement();
});

Это вызывает ошибку, потому что большинство функций расширения требует реализации возвращаемого типа IntoFuture, Тем не мение, () не реализует IntoFuture и завершив блок с помощью ; неявный тип возвращаемого значения (),

Тем не мение, IntoFuture реализован для Option а также Result,

Вместо того, чтобы просто произвольно удалять точки с запятой в надежде, что это каким-то образом волшебным образом скомпилирует ваш код, подумайте:

Вы должны возвращать что-то, что может быть преобразовано в Future с помощью IntoFuture,

Если у вас нет конкретного обещания, которое вы возвращаете, подумайте о возвращении Ok(()) просто сказать "это сделано" из вашего обратного вызова:

foo.then(|stream| {
    // ... Do random things here
    final_statement();
    return Ok(()); // <-- Result(()) implements `IntoFuture`.
});

Обратите внимание, что я заканчиваю этот блок явным оператором return; это намеренно Это типичный пример того, как эргономика "может опустить точку с запятой для неявного возврата объекта" является ощутимо вредной; завершить блок Ok(()); будет продолжать сбой с той же ошибкой.

Другие вопросы по тегам