溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Go語言中函數(shù)、閉包和遞歸是什么意思

發(fā)布時間:2021-09-18 02:16:43 來源:億速云 閱讀:152 作者:chen 欄目:編程語言

這篇文章主要講解了“Go語言中函數(shù)、閉包和遞歸是什么意思”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Go語言中函數(shù)、閉包和遞歸是什么意思”吧!

  GO函數(shù)特點:無需聲明原型。支持不定 變參。返回值類型寫在最后面,支持多返回值。支持命名返回參數(shù)。 支持匿名函數(shù)和閉包。函數(shù)也是一種類型,一個函數(shù)可以賦值給變量。不支持 嵌套 (nested) 一個包不能有兩個名字一樣的函數(shù)。不支持 重載 (overload) 。不支持 默認參數(shù) (default parameter)、可選參數(shù)。參數(shù)傳遞:無論是值傳遞,還引用傳遞,傳遞給函數(shù)的都是變量的副本,不過,值傳遞是值的拷貝。引用傳遞是地址的拷貝。

  使用關(guān)鍵字 func 定義函數(shù),左大括號依舊不能另起一行。

  Go函數(shù)聲明:

  package main

  import "fmt"

  func test(fn func() int) int {

  return fn()

  }

  // 定義函數(shù)類型。

  type FormatFunc func(s string, x, y int) string

  func format(fn FormatFunc, s string, x, y int) string {

  return fn(s, x, y)

  }

  func main() {

  s1 := test(func() int { return 100 }) // 直接將匿名函數(shù)當(dāng)參數(shù)。

  s2 := format(func(s string, x, y int) string {

  return fmt.Sprintf(s, x, y)

  }, "%d, %d", 10, 20)

  println(s1, s2)

  }

  // 返回結(jié)果

  // 100 10, 20

  GO函數(shù)參數(shù)

  函數(shù)可以通過兩種方式來傳遞參數(shù):

  值傳遞:指在調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進行修改,將不會影響到實際參數(shù)。

  引用傳遞:是指在調(diào)用函數(shù)時將實際參數(shù)的地址傳遞到函數(shù)中,那么在函數(shù)中對參數(shù)所進行的修改,將影響到實際參數(shù)。

  在默認情況下,Go 語言使用的是值傳遞,即在調(diào)用過程中不會影響到實際參數(shù)。

  注意1:無論是值傳遞,還是引用傳遞,傳遞給函數(shù)的都是變量的副本,不過,值傳遞是值的拷貝。引用傳遞是地址的拷貝,一般來說,地址拷貝更為高效。而值拷貝取決于拷貝的對象大小,對象越大,則性能越低。

  注意2:map、slice、chan、指針、interface默認以引用的方式傳遞。

  任意類型的不定參數(shù): 就是函數(shù)的參數(shù)和每個參數(shù)的類型都不是固定的。

  用interface{}傳遞任意類型數(shù)據(jù)是Go語言的慣例用法,而且interface{}是類型安全的。

  func myfunc(args ...interface{}) {

  }

  使用 slice 對象做變參時,必須展開。(slice...)

  package main

  import (

  "fmt"

  )

  func test(s string, n ...int) string {

  var x int

  for _, i := range n {

  x += i

  }

  return fmt.Sprintf(s, x)

  }

  func main() {

  s := []int{1, 2, 3}

  res := test("sum: %d", s...) // slice... 展開slice

  println(res)

  }

  GO函數(shù)返回值

  "_"標(biāo)識符,用來忽略函數(shù)的某個返回值

  Go 的返回值可以被命名,并且就像在函數(shù)體開頭聲明的變量那樣使用。

  返回值的名稱應(yīng)當(dāng)具有一定的意義,可以作為文檔使用。

  匿名函數(shù)

  匿名函數(shù)是指不需要定義函數(shù)名的一種函數(shù)實現(xiàn)方式。

  在Go里面,函數(shù)可以像普通變量一樣被傳遞或使用,Go語言支持隨時在代碼里定義匿名函數(shù)。

  匿名函數(shù)由一個不帶函數(shù)名的函數(shù)聲明和函數(shù)體組成。匿名函數(shù)的優(yōu)越性在于可以直接使用函數(shù)內(nèi)的變量,不必申明。

  package main

  import (

  "fmt"

  "math"

  )

  func main() {

  getSqrt := func(a float64) float64 {

  return math.Sqrt(a)

  }

  fmt.Println(getSqrt(4))

  }

  // 返回

  // 2

  上面先定義了一個名為getSqrt 的變量,初始化該變量時和之前的變量初始化有些不同,使用了func,func是定義函數(shù)的,可是這個函數(shù)和上面說的函數(shù)最大不同就是沒有函數(shù)名,也就是匿名函數(shù)。這里將一個函數(shù)當(dāng)做一個變量一樣的操作。

  Golang匿名函數(shù)可賦值給變量,做為結(jié)構(gòu)字段,或者在 channel 里傳送。

  package main

  func main() {

  // --- function variable ---

  fn := func() { println("Hello, World!") }

  fn()

  // --- function collection ---

  fns := [](func(x int) int){

  func(x int) int { return x + 1 },

  func(x int) int { return x + 2 },

  }

  println(fns[0](100))

  // --- function as field ---

  d := struct {

  fn func() string

  }{

  fn: func() string { return "Hello, World!" },

  }

  println(d.fn())

  // --- channel of function ---

  fc := make(chan func() string, 2)

  fc <- func() string { return "Hello, World!" }   println((<-fc)())   }   輸出結(jié)果:   Hello, World!   101   Hello, World!   Hello, World!   閉包

  閉包是由函數(shù)及其相關(guān)引用環(huán)境組合而成的實體(即:閉包=函數(shù)+引用環(huán)境)。

  函數(shù)與閉包

  Go的閉包

  package main

  import (

  "fmt"

  )

  func a() func() int {

  i := 0

  b := func() int {

  i++

  fmt.Println(i)

  return i

  }

  return b

  }

  func main() {

  c := a()

  c()

  c()

  c()

  fmt.Println("a() //不會輸出i")

  a() //不會輸出i

  c2 := a()

  c2()

  c2()

  c2()

  //輸出結(jié)果

  //1

  //2

  //3

  //a() //不會輸出i

  //1

  //2

  //3

  }

  這段代碼有兩個特點:

  函數(shù)b嵌套在函數(shù)a內(nèi)部 函數(shù)a返回函數(shù)b 這樣在執(zhí)行完var c=a()后,變量c實際上是指向了函數(shù)b(),再執(zhí)行函數(shù)c()后就會顯示i的值,第一次為1,第二次為2,第三次為3,以此類推。 其實,這段代碼就創(chuàng)建了一個閉包。因為函數(shù)a()外的變量c引用了函數(shù)a()內(nèi)的函數(shù)b(),就是說:

  當(dāng)函數(shù)a()的內(nèi)部函數(shù)b()被函數(shù)a()外的一個變量引用的時候,就創(chuàng)建了一個閉包。 在上面的例子中,由于閉包的存在使得函數(shù)a()返回后,a中的i始終存在,這樣每次執(zhí)行c(),i都是自加1后的值。 從上面可以看出閉包的作用就是在a()執(zhí)行完并返回后,閉包使得go的垃圾回收機制GC不會收回a()所占用的資源,因為a()的內(nèi)部函數(shù)b()的執(zhí)行需要依賴a()中的變量i。

  在給定函數(shù)被多次調(diào)用的過程中,這些私有變量能夠保持其持久性。變量的作用域僅限于包含它們的函數(shù),因此無法從其它程序代碼部分進行訪問。不過,變量的生存期是可以很長,在一次函數(shù)調(diào)用期間所創(chuàng)建所生成的值在下次函數(shù)調(diào)用時仍然存在。正因為這一特點,閉包可以用來完成信息隱藏,并進而應(yīng)用于需要狀態(tài)表達的某些編程范型中。

  下面來想象另一種情況,如果a()返回的不是函數(shù)b(),情況就完全不同了。因為a()執(zhí)行完后,b()沒有被返回給a()的外界,只是被a()所引用,而此時a()也只會被b()引 用,因此函數(shù)a()和b()互相引用但又不被外界打擾(被外界引用),函數(shù)a和b就會被GC回收。所以直接調(diào)用a();是頁面并沒有信息輸出。

  下面來說閉包的另一要素引用環(huán)境。c()跟c2()引用的是不同的環(huán)境,在調(diào)用i++時修改的不是同一個i,因此兩次的輸出都是1。函數(shù)a()每進入一次,就形成了一個新的環(huán)境,對應(yīng)的閉包中,函數(shù)都是同一個函數(shù),環(huán)境卻是引用不同的環(huán)境。這和c()和c()的調(diào)用順序都是無關(guān)的。

  遞歸函數(shù)

  遞歸,就是在運行的過程中調(diào)用自己。 一個函數(shù)調(diào)用自己,就叫做遞歸函數(shù)。

  構(gòu)成遞歸需具備的條件:

  1.子問題須與原始問題為同樣的事,且更為簡單。

  2.不能無限制地調(diào)用本身,須有個出口,化簡為非遞歸狀況處理。

  斐波那契數(shù)列(Fibonacci)

  這個數(shù)列從第3項開始,每一項都等于前兩項之和。

  package main

  import "fmt"

  func fibonaci(i int) int {

  if i == 0 {

  return 0

  }

  if i == 1 {

  return 1

  }

  return fibonaci(i-1) + fibonaci(i-2)

  }

  func main() {

  var i int

  for i = 0; i < 10; i++ {   fmt.Printf("%d\n", fibonaci(i))   }   }   輸出結(jié)果:   0   1   1   2   3   5   8   13   21   34   

到此,關(guān)于“Go語言中函數(shù)、閉包和遞歸是什么意思”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>


向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI