檢視原始碼 命名慣例
本文件是 Elixir 中命名慣例的參考,從大小寫到標點符號。
命名慣例依定義是 Elixir 語法的子集。慣例旨在遵循和設定語言和社群的最佳實務。如果您想要 Elixir 語法的完整參考,超越其慣例,請參閱 語法參考。
大小寫
定義變數、函式名稱、模組屬性等時,Elixir 開發人員必須使用 snake_case
some_map = %{this_is_a_key: "and a value"}
is_map(some_map)
別名通常用作模組名稱,它們是一個例外,因為它們必須大寫並寫在 CamelCase
中,例如 OptionParser
。對於別名,大寫字母保留在縮寫中,例如 ExUnit.CaptureIO
或 Mix.SCM
。
原子可以寫成 :snake_case
或 :CamelCase
,儘管慣例是在整個 Elixir 中使用 snake case 版本。
一般來說,檔案名稱遵循它們定義的模組的 snake_case
慣例。例如,MyApp
應該定義在 my_app.ex
檔案中。但是,這只是一個慣例。最終可以使用任何檔案名稱,因為它們不會以任何方式影響編譯的程式碼。
底線 (_foo
)
Elixir 在不同情況下依賴底線。
例如,不打算使用的值必須指定給 _
或以底線開頭的變數
iex> {:ok, _contents} = File.read("README.md")
函式名稱也可以以底線開頭。此類函式預設不會匯入
iex> defmodule Example do
...> def _wont_be_imported do
...> :oops
...> end
...> end
iex> import Example
iex> _wont_be_imported()
** (CompileError) iex:1: undefined function _wont_be_imported/0
由於此特性,Elixir 依賴以底線開頭的函式將編譯時元資料附加到模組。此類函式最常採用 __foo__
格式。例如,Elixir 中的每個模組都有 __info__/1
函式
iex> String.__info__(:functions)
[at: 2, capitalize: 1, chunk: 2, ...]
Elixir 還包括五個遵循雙底線格式的特殊形式:__CALLER__/0
、__DIR__/0
、__ENV__/0
和 __MODULE__/0
擷取關於目前環境的編譯時資訊,而 __STACKTRACE__/0
擷取目前例外狀況的堆疊追蹤。
尾隨驚嘆號 (foo!
)
尾隨驚嘆號(感嘆號)表示函數或巨集,其中失敗案例會引發例外狀況。
許多函數成對出現,例如 File.read/1
和 File.read!/1
。 File.read/1
會傳回成功或失敗的元組,而 File.read!/1
會傳回純值,否則會引發例外狀況
iex> File.read("file.txt")
{:ok, "file contents"}
iex> File.read("no_such_file.txt")
{:error, :enoent}
iex> File.read!("file.txt")
"file contents"
iex> File.read!("no_such_file.txt")
** (File.Error) could not read file no_such_file.txt: no such file or directory
當您想使用模式比對來處理不同結果時,建議使用沒有 !
的版本
case File.read(file) do
{:ok, body} -> # do something with the `body`
{:error, reason} -> # handle the error caused by `reason`
end
但是,如果您預期結果總會成功(例如,如果您預期檔案總是存在),則驚嘆號變體會更方便,並且會在失敗時引發更友善的錯誤訊息(而非失敗的模式比對)。
在思考函數的失敗案例時,我們嚴格思考在其網域內發生的錯誤,例如無法開啟檔案。例如,來自無效引數類型的錯誤,無論函數是否有驚嘆號,都必須始終引發。例外通常是 ArgumentError
或詳細的 FunctionClauseError
iex(1)> File.read(123)
** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1
The following arguments were given to IO.chardata_to_string/1:
# 1
123
Attempted function clauses (showing 2 out of 2):
def chardata_to_string(string) when is_binary(string)
def chardata_to_string(list) when is_list(list)
成對函數的更多範例: Base.decode16/2
和 Base.decode16!/2
、 File.cwd/0
和 File.cwd!/0
。
也有一些非成對函數,沒有非驚嘆號變體。驚嘆號仍表示它會在失敗時引發例外狀況。範例: Protocol.assert_protocol!/1
。
在巨集程式碼中, alias!/1
和 var!/2
上的驚嘆號表示 巨集衛生 已擱置一旁。
尾隨問號 (foo?
)
傳回布林值的函數會命名為尾隨問號。
範例: Keyword.keyword?/1
、 Mix.debug?/0
、 String.contains?/2
但是,傳回布林值且在守衛中有效的函數遵循另一個慣例,如下所述。
is_
前綴 (is_foo
)
守衛子句中允許的類型檢查和其他布林檢查會命名為 is_
前綴。
範例: Integer.is_even/1
、 is_list/1
這些函式和巨集遵循 Erlang 慣例,使用 is_
前綴,而不是尾隨問號,明確指出它們允許在防護子句中使用。
請注意,防護子句中無效的類型檢查不遵循此慣例。例如:Keyword.keyword?/1
。
特殊名稱
某些名稱在 Elixir 中具有特定含義。我們在下方詳細說明這些情況。
長度和大小
當您在函式名稱中看到 size
時,表示操作以常數時間執行(也寫為「O(1) 時間」),因為大小與資料結構一起儲存。
當您看到 length
時,表示操作以線性時間執行(「O(n) 時間」),因為必須遍歷整個資料結構。
換句話說,名稱中使用「size」一詞的函式無論資料結構是微小還是龐大,都會花費相同時間。相反地,名稱中包含「length」的函式會隨著資料結構大小增加而花費更多時間。