這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
[2012-05-19 翻譯自這裡, 對原文有所擴充, 也有所刪減. 著作權屬於原作者, 轉載必須保留此聲明.]
go是函數式程式設計語言嗎?不是, 當然不是.
那麼, go提供函數嗎?是的, 當然, 大多數程式設計語言都提供函數, go也不例外.
func SayHello() { fmt.Println("Hello")}
go使用關鍵字func定義函數, 並在函數體中編寫函數邏輯.
go函數可以接受參數嗎?額, 這個問題... 哦, 我懂了, 也許是我的SayHello函數給大家造成了錯覺, 我會改造My Code:
func SayHelloToSomeone(name string) { fmt.Println("Hello " + name + ".")}
函數SayHelloToSomeone接受一個string類型的參數name.
go函數是否可以有傳回值?是的, 是的, 是的! 就像數學意義上的函數一樣, go函數可以返回給調用者一些東西. 為了示範這一點, 我將重新編寫一個函數:
func GetGreeting (name string) string { greeting := "Hello " + name + "." return greeting}// testgreeting := GetGreeting("Bob")fmt.Println(greeting) //outputs "Hello Bob."
當然這沒有什麼, 其他語言也可以做到. 但是, 準備好接受驚喜了嗎? go函數的傳回值與其他類C語言有些不同, 比如, 你可以為傳回值指定名稱. 這帶來至少2個好處:1. 不需要在函數體中為傳回值定義變數.2. 無需在return語句後加上傳回值. go會自動將傳回值加上.
func GetGreeting (name string) (greeting string) { greeting = "Hello " + name + "." return}
GetGreeting函數為其傳回值指定了名稱: greeting. 在函數體中就可以直接使用greeting變數了, greeting其實就相當於函數中定義的一個局部變數. 而且如你所見, GetGreeting函數的return語句後面沒有加上傳回值, 因為go會自動將greeting變數的值返回給調用者.
go函數可以返回多個值嗎?這, 這, 你是異想天開嗎? 不過強大的go函數能夠做到這一點, 哈哈. 要知道可以有多個傳回值的函數可以避免很多醜陋的代碼, 下面是樣本:
type Stack struct { pos int data [10]int}func (s *Stack) Pop() (value int, ok bool) { if s.pos > 0 { s.pos-- ok = true value = s.data[s.pos] return } ok = false return}
代碼中首先定義了Stack類型, 並提供了Pop函數. Pop函數返回2個值: value和ok, 分別代表pop的值和pop操作是否成功.
go函數可以接受一個函數作為參數嗎?嗯, 我想你終於開始集中注意力了. 如果你是一個醫生, 你是否會對每次都需要向你的病人SayHello感到厭煩? 沒關係, go可以協助你. 首先需要定義新的資料結構:
type TormentList struct { patients []string}// 將[]string(string數組)封裝成TormentList類型的指標func NewTormentList(people []string) *TormentList { return &TormentList{people}}
接下來, 讓我們悄悄給TormentList類型增加Map方法:
func (g *TormentList) Map(f func(string)) {// 遍曆g.patients, 為其每個value調用f方法for _, val := range(g.patients) {f(val)}}
Map方法接受f函數作為其輸入參數, f函數接受一個string類型的值. 遍曆TormentList的病人, 並為每個病人調用f函數.現在已經做好了一切準備, 剩下的就是測試了:
patients := []string{"Anand", "David", "Ivan", "JoJo", "Jin", "Mon", "Peter", "Sachin"}gl := NewTormentList(patients)// 還記得上面定義的SayHelloToSomeone函數吧?gl.Map(SayHelloToSomeone)/*outputs the following:Hello Anand.Hello David.Hello Ivan.Hello JoJo.Hello Jin.Hello Mon.Hello Peter.Hello Sachin.*/
go函數的傳回值可以是函數嗎?讓我們先考慮一個現實問題: 假如你擁有一份吃過壽司的人的清單, 你是否能夠根據人名確定他是否在清單上? 這是個很簡單的問題, 你只需遍曆清單. 嗯, 如果你go的功底很弱, 不知道怎麼遍曆清單那怎麼辦? 沒關係, 我會給你提供一個刷選器:
func Screen(patients []string) func(string) bool { // 定義匿名函數並返回 return func(name string) bool { for _, soul := range patients { if soul == name { return true } } return false }}
Screen方法會將刷選的函數返回給調用方, 這樣你就可以不用懂怎麼去遍曆清單了, 你只需調用我返回給你的函數就可以:
// 吃過壽司的人的清單those_who_bought_sushi := []string{"Anand", "JoJo", "Jin", "Mon", "Peter", "Sachin"}// 得到刷選器函數bought_sushi := Screen(those_who_bought_sushi)// 調用刷選器函數就可以知道某人是否在清單上fmt.Println(bought_sushi("Anand")) // truefmt.Println(bought_sushi("Alex")) // false