【问题标题】:What are Elixir Bang Functions?什么是 Elixir Bang 功能?
【发布时间】:2016-01-24 06:52:28
【问题描述】:

在阅读 Phoenix 教程(在 Incoming Events 部分)时,我首先注意到一个带有结尾感叹号/bang(!) 的函数

def handle_in("new_msg", %{"body" => body}, socket) do
    broadcast! socket, "new_msg", %{body: body}
    {:noreply, socket}
end

后面的感叹号是什么意思?它有什么作用吗?我一直在四处寻找并尝试寻找,但我不确定我使用的术语是否正确。到目前为止,似乎仅作为约定的函数在失败时会引发错误,但它总是意味着这样。

我看到的唯一提及它出现在 Dave Thomas 的“Programming Elixir”中:

Identifiers in Elixir are combinations of upper and lower case ASCII 
characters, digits, and underscores. Function names may end with a 
question mark or an exclamation point.

the documentation 中也提到:

Notice that when the file does not exist, the version with ! raises an
error. The version without ! is preferred when you want to handle
different outcomes using pattern matching...

这些都没有解释这是否是其他长生不老药师或炼金术士或其他任何人使用的惯例。请帮忙。

【问题讨论】:

    标签: elixir phoenix-framework


    【解决方案1】:

    这个:

    请注意,当文件不存在时,带有 !提出一个 错误。没有的版本!当你想处理时是首选 使用模式匹配的不同结果...

    如果你看一下源代码会更清楚。函数名中的! 符号只是一个语法协议。如果您看到一个函数的名称中包含 ! 符号,这意味着可能存在同名的函数,但没有 ! 符号。这两个函数会做同样的事情,但它们会以不同的方式处理错误。

    没有! 的函数只会返回一个错误给你。您将需要知道一种错误并根据您的类型处理它。查看broadcast/3 函数(variant 没有!):

      def broadcast(server, topic, message) when is_atom(server),
        do: call(server, :broadcast, [:none, topic, message])
    

    它只是调用给定的服务器并返回它的结果。 broadcast!/3 函数会做同样的事情,但是:它将在没有 ! 的情况下调用 broadcast 函数,将检查其结果并引发 BroadcastError exception

      def broadcast!(server, topic, message) do
        case broadcast(server, topic, message) do
          :ok -> :ok
          {:error, reason} -> raise BroadcastError, message: reason
        end
      end
    

    【讨论】:

    • 感谢您花时间从 Phoenix 的源代码中提供一个很好的例子。它完美地回答了我的问题。我被困在你的答案和我选择的答案之间,因为两者都很好地解释了我的问题。我选择不选择这个只是因为它专注于 Phoenix 对 ! 的使用,不幸的是,在我的问题中没有表达,我对 Elixir 约定比 Phoenix 更感兴趣。
    • 我要吃我自己的话-并接受您的回答,因为它指出了@MoxleyStratton提到的一个重要细节-“爆炸约定适用于函数有两个版本的情况-- 一个会引发异常(bang 版本),一个不会。”
    【解决方案2】:

    这只是一个命名约定。检查这个答案 - What's the meaning of "!", "?", "_", and "." syntax in elixir

    ! - 如果函数遇到错误,将引发异常。

    一个很好的例子是 Enum.fetch!(它也有一个相同的 Enum.fetch 不会引发异常)。查找给定索引处的元素(从零开始)。如果给定位置超出集合范围,则引发 OutOfBoundsError。

    【讨论】:

    • 感谢您在 SO 上找到我一直在寻找的参考资料。我曾希望您链接的内容对官方文档有一些参考,但我想它必须这样做。我来自一个充满 PEP 文章的 Python 世界,其中不止几段专门讨论“为什么”,所以我有点失望,因为没有相同的公共思考过程,但这会必须做。
    • 乐于提供帮助,而且 elixir 每天都是新的并且每天都在改进,包括文档。所以我认为文档很快就会达到他们期望的水平。
    • 我仍然非常感谢您指出的来源,但是,现在(回首往事)我已将正确答案移至@0xAX,因为重点放在函数的双重版本上。我希望你同意这个决定。
    【解决方案3】:

    你基本上是对的,Marc - 按照惯例,如果出现问题,请说 DO RAISE AN ERROR。

    page 上有一种文档,其中讨论了文件访问 (向下滚动到短语 trailing bang

    【讨论】:

    • 我的主要问题是文档是顺便制作的,我们作为 Elixir 社区应该能够抓住其中的微妙之处。我很高兴我能够收集到一些东西,并且你提供了它被接受使用的 community documentation :) TY
    • 我发现这个答案具有误导性。阅读它,开发人员可以得出结论,当创建一个引发错误的函数时,它应该用 bang (!) 命名。这不是 bang 约定的意图。 @0xAX 在看到 bang 函数时说得对,“这意味着可能有一个同名的函数,但没有 ! 符号”。 bang 约定适用于函数有两种版本的情况——一种会引发异常(bang 版本),另一种不会。
    • @MoxleyStratton 回顾这个问题(并接受了答案)我同意你的观点(并且不同意我过去的决定)。
    猜你喜欢
    • 2013-02-14
    • 2013-08-03
    • 2021-03-09
    • 2011-06-26
    • 2017-05-14
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    相关资源
    最近更新 更多