当前位置: 首页 > 知识库问答 >
问题:

在使用期货时,有没有更符合人体工程学的语法?

劳豪
2023-03-14

以下是使用Tokio运行函数返回未来的示例:

use futures::sync::oneshot;
use futures::Future;
use std::thread;
use std::time::Duration;
use tokio;

#[derive(Debug)]
struct MyError {
    error_code: i32,
}

impl From<oneshot::Canceled> for MyError {
    fn from(_: oneshot::Canceled) -> MyError {
        MyError { error_code: 1 }
    }
}

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
    let (sx, rx) = oneshot::channel();
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(100));
        sx.send(100).unwrap();
    });
    return rx.map_err(|e| MyError::from(e));
}

fn main() {
    tokio::run(deferred_task().then(|r| {
        println!("{:?}", r);
        Ok(())
    }));
}

然而,当所讨论的函数(即< code>deferred_task)不是平凡的函数时,我编写的代码会变得更加复杂,因为< code >?操作似乎不容易与返回未来相混合:

fn send_promise_to_worker(sx: oneshot::Sender<i32>) -> Result<(), ()> {
    // Send the oneshot somewhere in a way that might fail, eg. over a channel
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(100));
        sx.send(100).unwrap();
    });
    Ok(())
}

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
    let (sx, rx) = oneshot::channel();
    send_promise_to_worker(sx)?; // <-------- Can't do this, because the return is not a result
    return rx.map_err(|e| MyError::from(e));
}

Future是一个结果,将其包装在结果中是没有意义的,它打破了impl Future返回类型。

相反,您会得到一个嵌套很深的链:

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
    let (sx, rx) = oneshot::channel();
    match query_data() {
        Ok(_i) => match send_promise_to_worker(sx) {
            Ok(_) => Either::A(rx.map_err(|e| MyError::from(e))),
            Err(_e) => Either::B(futures::failed(MyError { error_code: 2 })),
        },
        Err(_) => Either::B(futures::failed(MyError { error_code: 2 })),
    }
}

完整代码

结果越多,嵌套越深;到底是什么?运算符通常会解决。

我错过了什么吗?有没有一些语法糖来使这更容易?

共有2个答案

竺勇
2023-03-14

有没有一些语法糖来使这更容易?

是的,它被称为异步/等待,但它还没有准备好广泛消费。它只支持每晚,它使用稍微不同的期货版本,Tokio只通过互操作库支持,这会导致额外的语法开销,整个事情的文档仍然参差不齐。

以下是一些相关链接:

Rust中异步/等待的目的是什么
https://jsdw.me/posts/rust-asyncawait-preview/
这是一个很好的例子https://areweasyncyet.rs/

越狐若
2023-03-14

我看不出< code > async /< code > await 语法将如何明确地帮助您使用< code >要么。最终,您仍然需要返回一个具体类型,这就是< code >要么所提供的。然而,< code > async /< code > await 将减少对像< code>Future::map或< code>Future::and_then这样的组合器的需求。

另请参阅:

    < li >为什么impl trait不能用于返回多重/条件类型?

这就是说,您也不需要在此处使用

您有连续的< code>Result返回函数,所以您可以借鉴JavaScript的技巧,使用IIFE来使用< code >?操作员。然后,我们可以将组合的< code >结果提升到未来,并将其与来自接收器的未来链接起来:

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
    let (tx, rx) = oneshot::channel();

    let x = (|| {
        let _i = query_data().map_err(|_| MyError { error_code: 1 })?;
        send_promise_to_worker(tx).map_err(|_| MyError { error_code: 2 })?;
        Ok(())
    })();

    future::result(x).and_then(|()| rx.map_err(MyError::from))
}

据我所知,在未来,iLife可能会被try块取代。

您也可以走另一条路,将所有内容转换为未来:

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
    let (tx, rx) = oneshot::channel();

    query_data()
        .map_err(|_| MyError { error_code: 1 })
        .into_future()
        .and_then(|_i| {
            send_promise_to_worker(tx)
                .map_err(|_| MyError { error_code: 2 })
                .into_future()
        })
        .and_then(|_| rx.map_err(MyError::from))
}

这将有助于< code > async /< code > await 语法:

async fn deferred_task() -> Result<i32, MyError> {
    let (tx, rx) = oneshot::channel();

    query_data().map_err(|_| MyError { error_code: 1 })?;

    send_promise_to_worker(tx).map_err(|_| MyError { error_code: 2 })?;

    let v = await! { rx }?;

    Ok(v)
}

我还看到了通过向 Future 特征添加方法来构造 Either 的改进语法:

foo.left();
// vs
Either::left(foo);

但是,这不会出现在任何当前实现中。

一个Future是一个Result

不,不是的。

有两个相关的未来可以谈论:

  • 从期货0.1箱
  • 从(夜间)标准库

值得注意的是,Future::投票返回一种可以处于两种状态的类型:

  • 完成
  • 不完整

在期货板条箱中,“成功”和“失败”与“完成”相关联,而在标准库中则不然。在板条箱中,Result实现了IntoFuture,在标准库中,您可以使用Future::就绪。这两者都允许将Result转换为未来,但这并不意味着Result是一个未来,只不过是说Vec

有可能是<代码>?运算符(由< code>Try特征提供支持)将得到增强,自动从< code >结果转换为特定类型的< code >未来,或者< code >结果甚至将直接实现< code >未来,但是我没有听说过任何这样的计划。

 类似资料:
  • 所以我想要一个“Void Repository”,通过它可以访问不一定在实体上操作的存储过程。 但这当然不起作用,因为期望是一个实体。 有没有一种方法可以使用注释而无需创建虚拟实体,或者我是否坚持使用使用通过准备好的语句进行查询的已实现类? 因为老实说,这很难看:

  • 问题内容: 我正在使用我给定的语言环境获取自定义货币格式。但是,这始终包含我不需要的货币符号,我只想要给定语言环境的正确货币数字格式而没有货币符号。 做一个抛出一个异常.. 问题答案: 以下作品。这有点丑陋,但可以履行合同: 您还可以从货币格式中获取模式,删除货币符号,然后从新模式中重构新格式:

  • 问题内容: 我的意思是可以在Win32和Linux i386中都运行一个二进制文件吗? 问题答案: 这是不可能的,因为两种类型的格式有冲突: PE文件的开头两个字符必须是; ELF文件的开头四个字符必须为。 显然,您不能创建一个可以同时满足两种格式的文件。 回应有关多语言二进制文件同时作为16位COM文件和Linux ELF文件都有效的评论,这是有可能的(尽管COM文件实际上是DOS程序,而不是W

  • 问题内容: 我正在尝试根据语言环境获取货币符号。但是,它不是返回符号,而是返回代码。我有一个摘要: 对于 Locale.US, 它给出了符号,但是如果我替换 与 然后,用符号代替国家代码。为什么会这样以及如何获取符号? 编辑: 在寻找了一些答案之后,我想清除一下,设置一些特定的默认本地不是解决方案,因为 我需要一次显示所有可用的符号 。 例如 会给我欧元符号,但对于美元,它将给出代码,而不是美元符

  • 我已经将Python discord机器人部署到Heroku并启用了自动部署,但是当我转到参考资料时,我在任何地方都看不到worker,即使我已经部署了它。此外,我使用的是Github,而不是CLI (据我所知,没有文件)

  • 问题内容: 在过滤掉冗余信息时,我需要组合两个字符串集,这是我想出的解决方案,有没有人可以建议的更好方法?也许我忽略了内置的东西?谷歌没有任何运气。 问题答案: 由于a 不包含重复的条目,因此可以通过以下方式将两者合并: 两次添加都没有关系,该集合只包含一次元素…例如,不需要使用method 进行检查。