
文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载本篇技術指南以本倉庫 zh-tw/elixir.md繁體中文版為骨架並輔以根目錄英文原版 elixir.md 的補充內容完整覆蓋 Elixir 的基本型別、運算元、控制流程、模組與函式、結構與例外、平行處理等核心主題。讀者讀完後將能掌握 Elixir 的基礎語法與思維模式模式比對、不可變性、遞迴、Actor 並發模型並能直接在iexshell 中動手驗證每一個範例。Elixir 是一門建構在 Erlang 虛擬機BEAM之上的現代函數式語言。它完全與 Erlang 相容但採行了比較常見的語法並提供更多的功能——這正是本系列教學所要展示的以「可執行的註解程式碼」形式讓你在最短時間內熟悉這門語言的全貌。環境準備iex 與 elixirc在開始之前先認識兩個最重要的命令iexElixir 的互動式 shell進入後可以逐行輸入並執行 Elixir 表達式elixirc編譯器用來將.ex檔案中的模組編譯成 BEAM 虛擬機可執行的 bytecode。如果你已成功安裝 Elixir這兩個命令應已在你的PATH環境變數之下。本教學中的所有範例都可以直接貼進iex執行驗證。另外兩點關於註解的事實Elixir 的單行註解以井字號#開頭語言本身沒有多行註解的功能但你可以連續使用多個單行註解來達到相同效果。# 單行註解以井字號開頭 # 沒有多行註解的功能 # 但你可以連續使用多個單行 # 用 iex 來進入 Elixir shell # 用 elixirc 來編譯你的模組基本型別從數字到二進位數字與原子AtomsElixir 的數字分為整數與浮點數整數也支援十六進位寫法3 # 整數 0x1F # 整數十六進位等於 31 3.0 # 浮點數原子Atoms是不可變的字面常數其值就是自己的名稱以:開頭。原子在 Elixir/Erlang 生態系統中扮演「標籤」或「旗標」的角色例如:ok、:error這類回傳值慣例:hello # atom元組Tuples元組會存放在記憶體連續的區段裡適合存放固定數量、已知結構的資料{1,2,3} # tuple我們可以用elem函式來取得 tuple 中的元素索引從 0 開始elem({1, 2, 3}, 0) # 1串列Lists與的真實身分模式比對串列是用連結串列linked list實作的因此取出頭部head與尾部tail是最高效的操作[1,2,3] # list # 我們可以這樣取得串列的頭尾元素 [head | tail] [1,2,3] head # 1 tail # [2,3]這裡藏著 Elixir 最重要的概念之一在 Elixir 中就如同 Erlang 裡一樣代表的是模式比對pattern matching而非指派assignment。這代表將使用左手邊的模式pattern去與右手邊的值進行比對——上面取得串列頭尾元素的範例正是這個原理的應用。當模式比對無法找到合適的配對時就會回報錯誤例如下面兩個 tuple 的大小不一致# {a, b, c} {1, 2} # ** (MatchError) no match of right hand side value: {1,2}二進位Binaries、字串與字母串列Elixir 還有二進位型別字串與字母串列則是一體兩面的存在1,2,3 # binary hello # string hello # char list # 多行字串 Im a multi-line string. # Im a multi-line\nstring.\n三個容易被誤解、但必須釐清的關鍵事實字串皆使用 UTF-8 編碼因此可以直接存放非 ASCII 字元字串其實是以二進位實作而字母串列就只是單純的串列——這解釋了為什麼兩者用不同的運算元拼接?a在 Elixir 中會回傳字母a的 ASCII 整數97。héllò # héllò ?a, ?b, ?c # abc [?a, ?b, ?c] # abc ?a # 97拼接規則也因此而不同用來合併串列包含字母串列而合併二進位包含字串則要用[1,2,3] [4,5] # [1,2,3,4,5] hello world # hello world 1,2,3 4,5 # 1,2,3,4,5 hello world # hello world範圍Ranges範圍以開頭..結尾宣告頭尾都包含在內而且也可以進行模式比對1..10 # 1..10 lower..upper 1..10 # 可以對 range 進行模式比對 [lower, upper] # [1, 10]地圖Maps繁中版教學未包含 maps但這項重要的鍵值對資料結構出現在根目錄英文原版 elixir.md 中這裡一併補齊。Maps 以%{}宣告鍵可以是任何型別genders %{david male, gillian female} genders[david] # male # 以原子作為鍵的 maps 可以用點語法取值 genders %{david: male, gillian: female} genders.gillian # female運算元算術、布林與比較算術運算元1 1 # 2 10 - 5 # 5 5 * 2 # 10 10 / 2 # 5.0請特別注意在 Elixir 中/運算元永遠回傳浮點數。若需要回傳整數的除法用div要得到除法的餘數用remdiv(10, 2) # 5 rem(10, 3) # 1布林運算元嚴格版與寬鬆版Elixir 有兩套布林運算元行為差異值得留意or、and、not要求第一個參數必須為布林值true/false否則拋出錯誤||、、!接受任何型別的參數除了false與nil之外的值都會被當做 true。true and true # true false or true # true # 1 and true # ** (ArgumentError) argument error 1 || true # 1 false 1 # false nil 20 # nil !true # false比較運算元與全序Total Ordering用來比較的運算元有、!、、!、、、、1 1 # true 1 ! 1 # false 1 2 # true和!會嚴格比較整數與浮點數不會做型別寬鬆轉換1 1.0 # true 1 1.0 # falseElixir 的比較運算元允許跨型別比較這是少數例外因此可以建構混合型別的集合1 :hello # true [string, 123, :atom]所有型別的排序如下number atom reference functions port pid tuple list bit string引用 Erlang 之父 Joe Armstrong 的話「實際排序的先後並不重要但有明確排出全體順序的定義才是重要的。」——一個定義良好的全序關係讓排序、比對等操作在任何型別組合下都有明確的語義。控制流程if、case、cond 與 try/catchif表達式if false do This will never be seen else This will endcase以模式比對為核心的分支還記得模式比對嗎Elixir 中許多控制流程的結構都依賴模式比對來運作。case讓我們可以將一個值與許多模式進行比對從上到下依序嘗試case {:one, :two} do {:four, :five} - This wont match {:one, x} - This will match and bind x to :two in this clause _ - This will match any value end當我們不需要某個值的時候通常會將它比對成_萬用字元。例如我們只關心串列的第一個值的情況時[head | _] [1,2,3] head # 1若希望程式更好懂時我們可以這樣處理_tail同樣表示「忽略」但保留可讀性[head | _tail] [:a, :b, :c] head # :acond多重條件檢測cond讓我們可以同時檢測多個不同的條件用來代替巢狀的if表達式cond do 1 1 3 - I will never be seen 2 * 5 12 - Me neither 1 2 3 - But I will end把最後一個條件設為true來捕捉剩下的所有情況是很常見的作法本質上就是elsecond do 1 1 3 - I will never be seen 2 * 5 12 - Me neither true - But I will (this is essentially an else) endtry/catch與throw捕捉拋出的值try/catch用來捕捉拋出的值throw它也提供after子句無論是否有接到拋出的值最後都會調用其下的程式try do throw(:hello) catch message - Got #{message}. after IO.puts(Im the after clause.) end # Im the after clause # Got :hello模組與函式匿名函式注意那個句點square fn(x) - x * x end square.(5) # 25匿名函式的呼叫語法帶有一個句點square.(5)這是為了與具名函式呼叫square(5)區別。匿名函式也接受多個子句及防衛guards。Guards 可以對模式比對做更細緻的條件限制用when關鍵字來描述f fn x, y when x 0 - x y x, y - x * y end f.(1, 3) # 4 f.(-1, 3) # -3內建函式Elixir 也提供許多內建函式這些在預設的作用域下都可以使用is_number(10) # true is_list(hello) # false elem({1,2,3}, 0) # 1defmodule與def組織函式你可以用模組將多個的函式集合在一起。在模組裡用def來定義函式defmodule Math do def sum(a, b) do a b end def square(x) do x * x end end Math.sum(1, 2) # 3 Math.square(3) # 9要編譯這個Math模組時先將它存成math.ex再用elixirc進行編譯。在終端機輸入elixirc math.ex。編譯成功後就能在其他模組或iex中呼叫Math.sum/2、Math.square/1。defp私有函式在模組中我們可以用def宣告函式及用defp宣告私有private函式。使用def定義的函式可以在其它的模組中被調用私有的函式只能在這個模組內部調用defmodule PrivateMath do def sum(a, b) do do_sum(a, b) end defp do_sum(a, b) do a b end end PrivateMath.sum(1, 2) # 3 # PrivateMath.do_sum(1, 2) # ** (UndefinedFunctionError)Guards 與多子句第一個滿足的子句被調用函式宣告也支援用防衛條件及多個條件子句。當一個具有多個子句的函式被呼叫時第一個滿足該子句條件的函式會被調用。例如呼叫area({:circle, 3})時會呼叫下面定義的第二個area函式而非第一個defmodule Geometry do def area({:rectangle, w, h}) do w * h end def area({:circle, r}) when is_number(r) do 3.14 * r * r end end Geometry.area({:rectangle, 2, 3}) # 6 Geometry.area({:circle, 3}) # 28.25999999999999801048 # Geometry.area({:circle, not_a_number}) # ** (FunctionClauseError) no function clause matching in Geometry.area/1注意當所有子句都無法匹配例如圓的半徑不是數字會拋出FunctionClauseError——這是 Elixir 以模式比對驅動多型的典型寫法。遞迴不可變性的必然結果由於不可變特性immutability資料無法被原地修改因此遞迴在 Elixir 中扮演重要的角色。累加器accumulator是常見的遞迴模式defmodule Recursion do def sum_list([head | tail], acc) do sum_list(tail, acc head) end def sum_list([], acc) do acc end end Recursion.sum_list([1,2,3], 0) # 6模組屬性Module AttributesElixir 模組也支援屬性模組有內建一些屬性如moduledoc存放模組文件而你也可以定義自己的屬性defmodule MyMod do moduledoc 這是內建的屬性模組文件 my_data 100 # 這是自訂的屬性 IO.inspect(my_data) # 100 end管線運算元|資料流的自然串接繁中版未提及、但出現在英文原版 elixir.md 的|管線運算元允許你將前一個表達式的輸出作為第一個參數傳入下一個函式讓資料轉換流程由上而下、由左而右地閱讀Range.new(1,10) | Enum.map(fn x - x * x end) | Enum.filter(fn x - rem(x, 2) 0 end) # [4, 16, 36, 64, 100]這段程式先建立 1..10 的範圍平方每個元素再篩選出偶數結果——每個步驟的輸出直接流入下一步是 Elixir 函數式風格的招牌寫法。結構Structs與例外ExceptionsStructs帶有預設值的 map 擴展結構structs是 maps 的擴展是 Elixir 裡可以有預設值、編譯期檢查及多形polymorphism的資料結構。用defstruct宣告defmodule Person do defstruct name: nil, age: 0, height: 0 end joe_info %Person{ name: Joe, age: 30, height: 180 } # %Person{age: 30, height: 180, name: Joe}取值與更新更新產生的是新的struct原值不變——再次體現不可變性# 取得 name 的值 joe_info.name # Joe # 更新 age 的值 older_joe_info %{ joe_info | age: 31 } # %Person{age: 31, height: 180, name: Joe}例外處理try搭配rescue帶有rescue關鍵字的try區塊是用來進行例外處理的。raise拋出例外rescue依例外型別進行分支try do raise some error rescue RuntimeError - rescued a runtime error _error - this will rescue any error end # rescued a runtime error所有的異常都帶著一個訊息可以用x in [RuntimeError]的語法綁定例外物件並取出.messagetry do raise some error rescue x in [RuntimeError] - x.message end # some error平行處理Actor 模式Elixir 依靠actor 模式來進行平行處理。在 Elixir 中要寫出平行處理程式只需要三個基本要素建立行程process、發送訊息及接收訊息。注意這裡的 process 是 BEAM 虛擬機上的輕量行程並非作業系統執行緒。spawn建立行程我們用spawn函式來建立行程它接收一個函式當參數f fn - 2 * 2 end # #Functionerl_eval.20.80484245 spawn(f) # #PID0.40.0spawn會回傳一個 pid行程識別碼你可以利用這個 pid 來對該行程傳送訊息。我們會使用send運算元來傳送訊息。但首先我們要讓該行程可以接收訊息——這要用到receive機制來達成。receive監聽與處理訊息receive區塊能讓行程監聽接收到的訊息。每個receive do區塊只能接收一條訊息若要接收多條訊息時含有receive do的函式必須要在接到訊息後遞迴呼叫自己以再次進入receive do區塊defmodule Geometry do def area_loop do receive do {:rectangle, w, h} - IO.puts(Area #{w * h}) area_loop() {:circle, r} - IO.puts(Area #{3.14 * r * r}) area_loop() end end end組合起來send 訊息給行程編譯模組並在 shell 中創造一個行程來執行area_looppid spawn(fn - Geometry.area_loop() end) # #PID0.40.0 # 更簡潔的替代寫法 pid spawn(Geometry, :area_loop, [])對pid傳送訊息訊息會與接收區塊中的模式進行比對send pid, {:rectangle, 2, 3} # Area 6 # {:rectangle,2,3} send pid, {:circle, 2} # Area 12.56000000000000049738 # {:circle,2}self取得目前的 pidshell 本身也是一個行程process你可以用self拿到目前的 pidself() # #PID0.27.0Agent封裝可變狀態的行程英文原版 elixir.md 還介紹了 Agent——一種負責追蹤某個不斷變化數值的行程是狀態管理的高階抽象# 建立 agent傳入一個函式agent 的初始狀態即為該函式的回傳值 {:ok, my_agent} Agent.start_link(fn - [red, green] end) # Agent.get 接收 agent 名稱與一個 fn該 fn 會拿到目前的狀態 # 其回傳值即為你所取得的結果 Agent.get(my_agent, fn colors - colors end) # [red, green] # 用同樣的方式更新 agent 的狀態 Agent.update(my_agent, fn colors - [blue | colors] end)在 learnxinyminutes-docs 倉庫中的位置與延伸資源本篇教學的核心內容來自本倉庫的 zh-tw/elixir.md——這份文件是「Learn X in Y Minutes」系列見 README.md以「可執行的註解程式碼」形式教授程式語言的繁體中文翻譯由 Tai An Su 翻譯原作者為 Joao Marques 與 Dzianis Dashkevich。如果希望對照更多內容或從其他角度學習可以參閱elixir.md根目錄的英文原版包含 maps、|管線運算元與 Agent 等補充章節本文已將這些內容一併納入zh-cn/elixir.md簡體中文版適合對照繁中與簡中術語差異README.md了解本倉庫的貢獻方式與授權說明CC BY-SA 3.0。此外本倉庫還收錄了德文de/elixir.md、西班牙文es/elixir.md、法文fr/elixir.md、日文ja/elixir.md、俄文ru/elixir.md等十多種語言的 Elixir 教學版本方便不同語言背景的讀者交叉閱讀。結語從基本型別、模式比對到遞迴、Struct 與並發模型這份指南濃縮了 Elixir 最核心的語言特性。建議讀者把文中的所有範例逐一貼進iex實際執行親身體驗「是比對而非指派」、case/cond/函式多子句如何共同依賴模式比對以及spawn/send/receive三原語如何拼出 Actor 並發程式。當你能夠不看答案寫出sum_list的遞迴版本並讓兩個行程用訊息溝通時你就已經掌握了 Elixir 的入門精髓——接下來無論是探索 OTP、Phoenix 還是即時系統都有了紮實的語言基礎。赞分享文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载相关推荐1条命令搞定MPD/M3U8下载N_m3u8DL-RE能力拆解与实战指南1条命令搞定MPD/M3U8下载N_m3u8DL RE能力拆解与实战指南 拿到一个以 .mpd 结尾的课程链接你把它丢给 N_m3u8DL RE敲下一条命CLI音视频思源筆記 v2.8.10 完整解讀Windows 7 最終支援版、固定表格表頭與插件系統發布前的 API 演進思源筆記 v2.8.10 完整解讀Windows 7 最終支援版、固定表格表頭與插件系統發布前的 API 演進 思源筆記SiYuanv2.8.10 是一版知识管理知识库DDIA 第一版《資料系統基礎》導讀可靠性、資料模型、儲存引擎與編碼演化的完整知識地圖DDIA 第一版《資料系統基礎》導讀可靠性、資料模型、儲存引擎與編碼演化的完整知識地圖 《Designing Data Intensive Applicati文档教程上一篇TanStack Table 的 ColumnMeta 接口详解列级元数据的定义、类型化与实战用法下一篇DeepSeek Harness 请求可重建性设计让每个 LLM 请求都能从会话日志逐字节重建创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考