【发布时间】:2017-11-30 00:50:38
【问题描述】:
为什么case 在防护失败时不抛出运行时异常,而是静默失败从而隐藏潜在的错误?
例如为什么
case [] do
xs when hd(xs) -> "Won't match"
xs -> "Got #{xs}"
end
不会因为hd(xs)失败而返回参数错误?
更新:我提出这个问题是因为 Haskell 中的守卫不会发生同样的情况。比如函数
myfun x
| head([]) == x = 100
| otherwise = 200
在 GHCi 中调用时会产生
λ> myfun 6
*** Exception: Prelude.head: empty list
简而言之,与不对程序员隐藏异常的 Haskell 相比,Elixir 吃守卫中异常的行为背后的设计原理是什么?
谢谢,
【问题讨论】:
-
因为这是警卫的工作方式。如果它提出,这个案子永远不会作为案子。如果您想引发异常,请使用直接模式匹配。
-
@mudasobwa 充当
case是什么意思?对我来说,在程序中伪装错误的东西是语言的设计缺陷。 -
根据您的逻辑,所有允许救援异常的语言都有设计流程。它不会伪装任何东西。它显式地捕获任何可能的异常并返回
false。这使得守卫更简洁,这是完美的。这是一个守卫,而不是一段随机的代码。 对你来说,它似乎是一个设计流程,与现实中存在的设计流程无关。 -
@mudasobwa 不,不,这不是明确的捕获,而是隐含的捕获。如果你的程序在一个守卫之外访问一个空列表的头部并且语言会像 Elixir 那样为你抛出一个运行时异常,你是否不考虑一个错误?或者你更喜欢在这种情况下获得零并继续前进?如果 Elixir 在守卫之外抛出异常,它在守卫内部的行为应该与此一致。
-
“守卫内部的行为应该与此保持一致” — 真的吗?这是为什么?因为你不熟悉
guards?guard的捕获是一个明确的捕获,正如文档中到处都清楚地说明的那样。这是一个契约:rescue和guard都是显式捕获。忍受它:)