為什么說Go的函數(shù)是“一等公民”?


什么是一等公民?
我們先來看下相關概念

A language construct is said to be a FirstClass value in that language when there are no restrictions on how it can be created and used: when the construct can be treated as a value without restrictions.

翻譯:如果對如何創(chuàng)建和使用它沒有任何限制:當該結(jié)構可以被視為沒有限制的值時,該語言結(jié)構被稱為該語言中的 FirstClass 值。(即”一等公民“)

FirstClass features can be stored in variables, passed as arguments to functions, created within functions and returned from functions. In dynamically typed languages, a FirstClass feature can also have its type examined at run-time.

翻譯:“一等公民”的特性是可以存儲在變量中,可以作為參數(shù)傳遞給函數(shù),可以在函數(shù)中創(chuàng)建并作為返回值從函數(shù)返回。

Go的函數(shù)滿足了“一等公民”的特性定義,所以說Go的函數(shù)是”一等公民“。

下面帶大家先了解下函數(shù)基本定義,然后再通過案例來論證下這些特性:

函數(shù)基本定義
func 函數(shù)名(參數(shù))(返回值){
    函數(shù)體
}
復制代碼
函數(shù)名:由字母、數(shù)字、下劃線組合。注意數(shù)字不要作為開頭;
參數(shù):非必填??芍付▍?shù)名稱和類型,也可以使用可變參數(shù)...的寫法,接收一個切片;
返回值:非必填。只返回一個值時直接定義返回類型,返回多個值或者給返回值命名,這需要使用()和,進行定義。
簡單示例:

func main() {
  fmt.Println(sum(10, 20))   //30
  fmt.Println(sum2())        //0
  fmt.Println(sum2(10, 20))  //30
  fmt.Println(sum3(100, 20)) //120
}

//指定參數(shù)
func sum(a, b int) int {
  return a + b
}

//可變參數(shù),num是個切片,接受0~n個參數(shù)
func sum2(num ...int) int {
  ret := 0
  for _, v := range num {
    ret += v
  }
  return ret
}

//返回值命名
func sum3(a, b int) (ret int) {
  ret = a + b
  return
}
復制代碼
特性1:可以存儲在變量中
提供兩種寫法:

寫法1:定義函數(shù)類型的變量

type calcFoo func(int, int) int //定義函數(shù)類型

func main() {
  var add calcFoo
  add = addFoo
  fmt.Printf("type of c:%T\n", add) //type of c:main.calcFoo
  fmt.Println(add(100, 200))        //300
}

func addFoo(a, b int) int {
  return a + b
}
復制代碼
備注:只要滿足接收兩個int類型參數(shù)和返回一個int類型值的函數(shù),都可以認為是calcFoo類型的函數(shù)

寫法2:使用匿名函數(shù),賦值給變量(備注:匿名函數(shù)即沒有函數(shù)名的函數(shù),有兩種使用方式)

//方式1:變量存儲
add := func(a, b int) int {
  return a + b
}
fmt.Println(add(100, 200)) //300

//方式2:直接執(zhí)行
c := func(a, b int) int {
  return a + b
}(22, 33)
fmt.Println(c) //55
復制代碼
特性2:可以作為參數(shù)傳遞給函數(shù)
可以先定義好對應函數(shù),也可以直接使用匿名函數(shù),然后作為參數(shù)傳遞給函數(shù)

func main() {
  //使用定義好的函數(shù),進行傳遞
  fmt.Println(addFoo2(11, 22, addFoo)) //33
 
  //使用匿名函數(shù),進行傳遞
  fmt.Println(addFoo2(11, 22, func(a int, b int) int { return a + b })) //33
}

func addFoo(a, b int) int {
  return a + b
}

func addFoo2(a, b int, foo func(int, int) int) int {
  return foo(a, b)
}
復制代碼
特性3:可以在函數(shù)中創(chuàng)建并作為返回值從函數(shù)返回
這個其實就是閉包的用法,獲取到返回來的func,然后傳入?yún)?shù),進行操作

func main() {
  //例子1:
  a1 := adder(10)
  fmt.Println(a1(10), a1(20), a1(30)) //20 40 70

  //例子2:
  a2 := adder2()
  fmt.Println(a2(10), a2(20), a2(30)) //10 30 60
  a3 := adder2()                      //注意:a3是重新聲明的,base被初始化為0,并不會沿用a2的base值,因為生命周期不同
  fmt.Println(a3(10), a3(20), a3(30)) //10 30 60
}

func adder(base int) func(int) int {
  return func(num int) int {
    base += num
    return base
  }
}

func adder2() func(int) int {
  var base int
  return func(num int) int {
    base += num
    return base
  }
}
復制代碼
總結(jié)
這篇文章介紹了”一等公民“的定義和特性,并且通過案例論證了Go的函數(shù)是符合”一等公民“特性的

可以存儲在變量中、可以作為參數(shù)傳遞給函數(shù)、可以在函數(shù)中創(chuàng)建并作為返回值從函數(shù)返回。

使用好這些特性,可以讓我們業(yè)務代碼更加簡潔,提高代碼的健壯性和可讀性。

你還有哪些想看的Go語言知識點?歡迎在評論區(qū)留言~




請前往:http://lygongshang.com/TeacherV2.html?id=365