Как использовать сокет, содержащийся в типе Result, в цепочке фьючерсов? - PullRequest
0 голосов
/ 24 августа 2018

У меня есть следующий рабочий код из документов Tokio, который я немного изменил:

// Task
let connection = io::read_exact(socket, buf_read)
    .and_then(|(socket, buf_read)| {
        println!("Do something with the received data...");
        for b in &buf_read {
            println!("{}", b);
        }

        // Write to the socket
        let buf_write = vec![19; 30];
        io::write_all(socket, buf_write)
    })
    .then(|res| {
        println!("{:?}", res); // Just for testing
        //Output: Ok((TcpStream, [19, 19, 19, ...]

        println!("Send data...");
        let buf_write = vec![18; 10]; // Fill the buffer with some data
        //
        //How to use the socket contained in res to write the data to the socket
        //    
        Ok(())
    });

В упомянутых документах

Обратите внимание, чтоres - это Result, который содержит оригинальный сокет.Это позволяет нам выполнять дополнительные операции чтения или записи в одном и том же сокете.

Как использовать сокет, содержащийся в Result, для записи данных в сокет?

1 Ответ

0 голосов
/ 24 августа 2018

Пожалуйста, начните с перечитывания Язык программирования Rust , в частности, главы о Восстанавливаемые ошибки с результатом . Затем перечитайте документацию по библиотеке, которую вы используете .

Future::then, мина:

fn then<F, B>(self, f: F) -> Then<Self, B, F>
where
    F: FnOnce(Result<Self::Item, Self::Error>) -> B,
    B: IntoFuture,
    Self: Sized,

Цепочка вычислений для того, когда будущее закончится, передавая результат будущего до предусмотренного закрытия f.

Эта функция может использоваться для обеспечения выполнения вычислений независимо от того, вывод о будущем. Предоставленное закрытие будет принесло Result как только будущее будет завершено.

Сравните это с другой функцией, которую вы используете, Future::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, 

Выполнить другое будущее после того, как это будет разрешено успешно .

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


Одно из решений - обработать его только в случае успеха через and_then:

extern crate tokio; // 0.1.7

use tokio::{io, net::TcpStream, prelude::*};

fn example(socket: TcpStream, buf_read: Vec<u8>) {
    io::read_exact(socket, buf_read)
        .and_then(|(socket, buf_read)| {
            let buf_write = vec![19; 30];
            io::write_all(socket, buf_write)
        }).and_then(|(socket, data)| {
            let buf_write = vec![18; 10];
            io::write_all(socket, buf_write)
        });
    // TODO: use future somehow 
}

Если вы хотите знать о сбое, вы можете продолжать использовать then, но вам придется как-то обработать ошибку:

fn example(socket: TcpStream, buf_read: Vec<u8>) {
    io::read_exact(socket, buf_read)
        .and_then(|(socket, buf_read)| {
            let buf_write = vec![19; 30];
            io::write_all(socket, buf_write)
        }).then(|res| match res {
            Ok((socket, data)) => {
                let buf_write = vec![18; 10];
                io::write_all(socket, buf_write)
            }
            Err(e) => {
                // Do something with the error and return another
                // future that's type-compatible
                unimplemented!()
            },
        });
    // TODO: use future somehow
}

Смотри также:

...