Как использовать сокет, содержащийся в типе Result, в цепочке фьючерсов?

У меня есть следующий рабочий код из документации 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, для записи данных в сокет?


person dergroncki    schedule 24.08.2018    source источник
comment
Возможно, вам будет интересно использовать split также.   -  person squiguy    schedule 24.08.2018
comment
Можете ли вы объяснить, как здесь использовать сплит? Как видно из моего кода, println! ({:?}, res) возвращает Ok ((TcpStream, [19, 19, 19, ...]. Как я могу получить доступ к содержащемуся TcpStream и записать данные в сокет?   -  person dergroncki    schedule 24.08.2018
comment
Просмотрите, как создать минимальный воспроизводимый пример, а затем отредактируйте свой вопрос, чтобы включить его. Мы не можем сказать, какие ящики, типы, черты, поля и т. Д. Присутствуют в коде. Попробуйте создать что-то, что воспроизводит вашу ошибку на Rust Playground, или вы можете воспроизвести это в совершенно новом Cargo проект. Также есть советы MCVE для Rust.   -  person Shepmaster    schedule 24.08.2018


Ответы (1)


Для начала перечитайте Язык программирования 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,

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

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

Сравните это с другой функцией, которую вы используете, _ 5_, акцент мой:

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
}

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

person Shepmaster    schedule 24.08.2018