【问题标题】:Why would I use divergent functions?为什么我要使用不同的函数?
【发布时间】:2015-06-26 21:02:21
【问题描述】:

阅读 Rust 书,我遇到了an interesting topic — divergent functions

Rust 有一些用于“发散函数”的特殊语法,它们是 不返回的函数:

fn diverges() -> ! {
    panic!("This function never returns!");
}

发散函数可以用作任何类型:

let x: i32 = diverges();
let x: String = diverges();

发散函数的用例是什么?书上说

panic!() 导致当前执行线程崩溃 给定的消息。因为这个函数会导致崩溃,所以它永远不会 返回,所以它的类型为!

这是有道理的,但我想不出还有什么地方可以使用发散函数,而且它似乎非常本地化为 panic!。我知道肯定有一些有用的场景可以解释为什么他们引入了不同的功能。在 Rust 中我可能会在哪里看到不同的函数?

【问题讨论】:

    标签: rust


    【解决方案1】:

    它有多种用途。它可用于旨在恐慌或退出程序的功能。 panic!() 本身就是这样一个函数,但它也可以应用于包装了 panic!() 的函数,例如打印出更详细的错误信息然后恐慌。

    它也可以用于永不返回的函数。如果一个函数进入一个无限循环,例如服务器的主循环,因此永远不会返回,它可以这样定义。

    另一个可能的用途是 Unix exec family of functions 的包装器,其中当前进程被正在执行的进程替换。

    拥有这样的类型很有用,因为它与所有其他类型兼容。为了类型安全,Rust 必须确保 matchif 语句的所有分支都返回相同的类型。但是如果有一些分支无法访问或指示错误,则需要某种方式来抛出错误,该错误将与其他分支返回的类型统一。因为! 统一了所有类型,所以可以在任何情况下使用。

    目前有一个interesting RFC(和discussion)(部分)支持expanding the places where ! can be used,认为它应该被视为像()这样的完整类型; ! 是一个没有与所有其他类型统一的值的类型,而 () 是一个具有单个值的不同类型。我不确定我是否同意完整的 RFC,但将 ! 视为成熟类型的讨论很有趣,我认为可以与 RFC 的其余部分分开提出。

    更新:由于我写了上面的内容,RFC 中关于将! 提升为完整类型的部分是split into a separate RFC and merged,并且是in the process of being implemented(目前在后面的夜间构建中可用一个特征门)。作为一种成熟的类型,它可以在更多的上下文中使用,例如Result<T, !> 表示永远不会失败的结果,或者Result<!, E> 表示永远不会成功的结果。这些在通用上下文中很有用;如果你有一些特性需要一个方法来返回结果,但对于那个特定的实现它只能成功,你不需要填写一些虚拟错误类型。

    【讨论】:

      【解决方案2】:

      正如您从书中引用的那样,Rust 的 bottom type 用于指定不返回的函数。这包括:

      • panic!()
      • 永远循环
      • 退出程序(从main()返回除外),如exit(),其签名为pub fn exit(code: i32) -> !

      【讨论】:

      • 我最喜欢的是unimplemented!()unreachable!()
      【解决方案3】:

      最常见的用例之一是在#![no_std] 环境中启用(自定义)恐慌:

      #![panic_handler]
      fn panic(_info: &PanicInfo) -> ! {
          loop{}
      }
      

      你会在Philipp Oppermann’s Rust OS development tutorial 中看到很多不同的功能,因为当你在低级别工作时,返回会使 CPU 发生三重故障并导致它重置(或者用外行的话来说,导致立即重启)。

      【讨论】:

        猜你喜欢
        • 2023-03-04
        • 1970-01-01
        • 2017-02-16
        • 2017-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-07
        相关资源
        最近更新 更多