保護條款的基本用法
在 Elixir 中,可以建立具有相同名稱的函式的多個實現,並指定在呼叫函式之前將應用於函式的引數的規則,以便確定要執行的實現。
這些規則由關鍵字 when
標記,它們位於函式定義中的 def function_name(params)
和 do
之間。一個簡單的例子:
defmodule Math do
def is_even(num) when num === 1 do
false
end
def is_even(num) when num === 2 do
true
end
def is_odd(num) when num === 1 do
true
end
def is_odd(num) when num === 2 do
false
end
end
假設我用這個例子執行 Math.is_even(2)
。is_even
有兩種實現方式,具有不同的保護條款。系統將按順序檢視它們,並執行引數滿足 guard 子句的第一個實現。第一個指定 num === 1
不是真的,所以它移動到下一個。第二個指定 num === 2
,這是真的,所以這是使用的實現,返回值將是 true
。
如果我執行 Math.is_odd(1)
怎麼辦?系統檢視第一個實現,並看到由於 num
是 1
,第一個實現的保護條款得到滿足。然後它將使用該實現並返回 true
,而不是在檢視任何其他實現。
警衛在他們可以執行的操作型別方面受到限制。 Elixir 文件列出了每個允許的操作 ; 簡而言之,它們允許比較,數學,二元運算,型別檢查(例如 is_atom
)和一些小的便利功能(例如 length
)。可以定義自定義保護子句,但它需要建立巨集,最好留給更高階的指南。
請注意,警衛不會丟擲錯誤; 它們被視為保護條款的正常故障,系統繼續檢視下一個實現。如果你發現在呼叫帶有 params 的保護函式時你得到了什麼,那麼你期望它可能會起作用,那麼你期望工作的一個保護條款就是丟擲一個被誤吞的錯誤。
要自己看一下這個,建立然後呼叫一個沒有意義的保護函式,例如這個試圖除以零的函式:
defmodule BadMath do
def `divide(a)` when a / 0 === :foo do
:bar
end
end
呼叫 BadMath.divide("anything")
將提供有點無益的錯誤 (FunctionClauseError) no function clause matching in BadMath.divide/1
- 而如果你試圖直接執行 "anything" / 0
,你會得到一個更有用的錯誤:(ArithmeticError) bad argument in arithmetic expression
。