《Elixir 101》函式與回傳值

更新於 發佈於 閱讀時間約 11 分鐘
raw-image

最近又重新開始學 Elixir,這時遇到一個問題:

在 Elixir 裡面要怎麼建立函式,還有函式要怎麼回傳值?

首先這要從 Elixir 有兩種函數類型說起:

  • 匿名函式(Anonymous Functions)
  • 具名函示(Named Functions)

匿名函式 (Anonymous Functions)

匿名函式 (Anonymous Functions),通常指的是這個函式無需有函示的識別符號(identifier)。在有些語言實作上,被稱為 lambda表示式(Pyhton),或者是 閉包(closures) (Rust)。

在 Elixir 裡,匿名函式是宣告一個變數,然後將函式用 fn ... end 包裹起來。

例如我們宣告一個叫 hello_world 的匿名函式,裡面是向顯示器顯示 Hello World ,那我們可以寫作:

hello_world = fn() -> IO.puts "Hello World" end

這時候我們該如何執行這個函式呢?

在其他語言中,可能會很自然的加上 () 作為執行函式的句法,例如上方的 hello_world 變成 hello_world() 來執行。接著就會在 Elixir 中發生錯誤。例如我們在 iex 中試試看:

$ iex
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> hello_world = fn() -> IO.puts "Hello World" end
#Function<21.126501267/0 in :erl_eval.expr/5>
iex(2)> hello_world()
** (CompileError) iex:2: undefined function hello_world/0

在 Elixir 中,必須加入 . (dot) 來執行這個匿名函式(. (dot) 在 Elixir 裡面也是一個運算符號,基於本篇主題,留待下次再說明)。所以執行上方範例的 hello_world 就要變成:

hello.()

這時候我們在 iex 在實驗一次,就可以知道成功執行啦!

$ iex
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> hello_world = fn() -> IO.puts "Hello World" end
#Function<21.126501267/0 in :erl_eval.expr/5>
iex(2)> hello_world.()
Hello World
:ok
iex(3)>

具名函式(Named Functions)

相對於匿名函式,具名函式具有識別符。不過在 Elixir 裡面宣告一個具名函式,和其他語言一些不同。例如在 JavaScript 我們可以直接用 function 語法宣告一個 helloWorld 的具名函式:

function helloWorld(){
console.log('hello world');
}

但在 Elixir 裡面我們可以這樣做嗎?是不是可以將匿名函式的 fn...end 語法直接拿來宣告為:

fn hello_world = () -> IO.puts "hello world"

答案是不能的。

在 Elixir 裡,具名函式的運作範圍僅限於模組(module)。換言之,必須將函式定義在 module 裡。例如我們定義一個 MyModule 名稱的 module,裡面有一個具名函式稱為 hello_world :

defmodule MyModule do
def hello_world() do
IO.puts "hello world"
end
end

當我們在 module 裡面定義好一個具名函式,這時候我們一樣就可以用 . (dot) ,來呼叫這個 module 裡面特定的具名函式。例如上述案例,我們要呼叫 MyModule 裡面的 hello_world 我們就是:

MyModule.hello_world()

在 iex 裡面實驗一次:

$ iex
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> defmodule MyModule do
...(1)> def hello_world do
...(1)> IO.puts "hello world"
...(1)> end
...(1)> end
{:module, MyModule,
<<70, 79, 82, 49, 0, 0, 4, 104, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 149,
0, 0, 0, 15, 15, 69, 108, 105, 120, 105, 114, 46, 77, 121, 77, 111, 100, 117,
108, 101, 8, 95, 95, 105, 110, 102, 111, ...>>, {:hello_world, 0}}
iex(2)> MyModule.hello_world()
hello world
:ok
iex(3)>

函式的回傳值

以上介紹了兩種函示:匿名函式以及具名函式。那我們在函式中,要怎麼回傳函式的運算值呢?

在程式語言中,函式回傳值主要有兩種表示方式:

  • 用 return 或相類似的語法
  • 回傳值為函式結構中最後的表示式

第一種方式就例如 JavaScript,在函式結構中用 return 語法回傳函式運算值,如果未設定的話,就是回傳 undefined:

function helloWorld(shouldReturn){
if(shouldReturn){
return 'hello world';
}
}

console.log(helloWorld(true)); // 將輸出 'hello world'
console.log(helloWorld(false)); // 將輸出 undefined

而在 Elixir 裡,則是採用第二種方式,將函式結構中最後表示式作為回傳值。如果沒有,則回傳 nil ,即空值。

以之前 MyModule 為例,我們新增另一個 hello 具名函式,而他的函式結構中未有任何程式碼。並將 hello_world 中的 IO.puts "hello world" 改為 "hello world":

defmodule MyModule do
def hello_world() do
"hello world"
end

def hello() do
end
end

這時候 hello_world 將回傳字串值 hello_world ,而 hello 將僅回傳 nil。我們可以在 iex 中試一下:

$ iex
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> defmodule MyModule do
...(1)> def hello_world() do
...(1)> 'hello world'
...(1)> end
...(1)> def hello() do
...(1)> end
...(1)> end
{:module, MyModule,
<<70, 79, 82, 49, 0, 0, 4, 120, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 144,
0, 0, 0, 15, 15, 69, 108, 105, 120, 105, 114, 46, 77, 121, 77, 111, 100, 117,
108, 101, 8, 95, 95, 105, 110, 102, 111, ...>>, {:hello, 0}}
iex(2)> MyModule.hello_world()
'hello world'
iex(3)> MyModule.hello()
nil
iex(4)>

參考文獻


留言
avatar-img
留言分享你的想法!
avatar-img
工法人的沙龍
1會員
5內容數
身為一個軟體工程師,在現今如此快速變化的世界中,該如何確保自生不被滅亡呢?
你可能也想看
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
👨‍💻簡介 在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。
Thumbnail
👨‍💻簡介 在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。
Thumbnail
在第五堂課中,我們將探討 Python 中的函式(functions)。 函式是一種讓我們可以將程式碼塊組織成一個獨立、可重複使用的單元的方式。 函式可以接受參數 (arguments) 並返回一個結果。 讓我們在新的文件 functions.py 中學習如何定義和使用函式。
Thumbnail
在第五堂課中,我們將探討 Python 中的函式(functions)。 函式是一種讓我們可以將程式碼塊組織成一個獨立、可重複使用的單元的方式。 函式可以接受參數 (arguments) 並返回一個結果。 讓我們在新的文件 functions.py 中學習如何定義和使用函式。
Thumbnail
在第五課中,我們將探討 Python 中的函式(functions)。 函式是一種讓我們可以將程式碼塊組織成一個獨立、可重複使用的單元的方式。函式可以接受參數 (arguments) 並返回一個結果。
Thumbnail
在第五課中,我們將探討 Python 中的函式(functions)。 函式是一種讓我們可以將程式碼塊組織成一個獨立、可重複使用的單元的方式。函式可以接受參數 (arguments) 並返回一個結果。
Thumbnail
我們將探索函式的定義和調用,這是程式設計中非常重要且強大的概念,它可以將大型程式切割成小的、可重複使用的函式。讓我們一起來了解吧!函式的定義、呼叫和返回值是學習函式的核心。
Thumbnail
我們將探索函式的定義和調用,這是程式設計中非常重要且強大的概念,它可以將大型程式切割成小的、可重複使用的函式。讓我們一起來了解吧!函式的定義、呼叫和返回值是學習函式的核心。
Thumbnail
所以寫程式的人都知道的一句話:「Hello World」,每一個學程式語言開始的時候都是從這句話開始的,我們也不免俗的來上這一句,從Hello World來看看智能合約入門是個什麼樣子。
Thumbnail
所以寫程式的人都知道的一句話:「Hello World」,每一個學程式語言開始的時候都是從這句話開始的,我們也不免俗的來上這一句,從Hello World來看看智能合約入門是個什麼樣子。
Thumbnail
隨著程式的功能愈來愈複雜,程式碼也愈來愈多,若程式從頭寫到尾沒有任何的段落,可讀性會愈來愈差,甚至會發現同樣的一段程式碼重覆很多遍,因為類似的功能區塊在程式中可能會一再出現。這樣的程式碼不利於多人的協作開發,即使是寫作者本身在一段時間後回來看,可能也難以一眼就掌握程式的主要架構。
Thumbnail
隨著程式的功能愈來愈複雜,程式碼也愈來愈多,若程式從頭寫到尾沒有任何的段落,可讀性會愈來愈差,甚至會發現同樣的一段程式碼重覆很多遍,因為類似的功能區塊在程式中可能會一再出現。這樣的程式碼不利於多人的協作開發,即使是寫作者本身在一段時間後回來看,可能也難以一眼就掌握程式的主要架構。
Thumbnail
int main()、註解//、include 、命名空間、using namespace
Thumbnail
int main()、註解//、include 、命名空間、using namespace
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News