您好,登錄后才能下訂單哦!
這篇文章主要講解了“Go語言中函數、閉包和遞歸是什么意思”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Go語言中函數、閉包和遞歸是什么意思”吧!
GO函數特點:無需聲明原型。支持不定 變參。返回值類型寫在最后面,支持多返回值。支持命名返回參數。 支持匿名函數和閉包。函數也是一種類型,一個函數可以賦值給變量。不支持 嵌套 (nested) 一個包不能有兩個名字一樣的函數。不支持 重載 (overload) 。不支持 默認參數 (default parameter)、可選參數。參數傳遞:無論是值傳遞,還引用傳遞,傳遞給函數的都是變量的副本,不過,值傳遞是值的拷貝。引用傳遞是地址的拷貝。
使用關鍵字 func 定義函數,左大括號依舊不能另起一行。
Go函數聲明:
package main
import "fmt"
func test(fn func() int) int {
return fn()
}
// 定義函數類型。
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 }) // 直接將匿名函數當參數。
s2 := format(func(s string, x, y int) string {
return fmt.Sprintf(s, x, y)
}, "%d, %d", 10, 20)
println(s1, s2)
}
// 返回結果
// 100 10, 20
GO函數參數
函數可以通過兩種方式來傳遞參數:
值傳遞:指在調用函數時將實際參數復制一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。
引用傳遞:是指在調用函數時將實際參數的地址傳遞到函數中,那么在函數中對參數所進行的修改,將影響到實際參數。
在默認情況下,Go 語言使用的是值傳遞,即在調用過程中不會影響到實際參數。
注意1:無論是值傳遞,還是引用傳遞,傳遞給函數的都是變量的副本,不過,值傳遞是值的拷貝。引用傳遞是地址的拷貝,一般來說,地址拷貝更為高效。而值拷貝取決于拷貝的對象大小,對象越大,則性能越低。
注意2:map、slice、chan、指針、interface默認以引用的方式傳遞。
任意類型的不定參數: 就是函數的參數和每個參數的類型都不是固定的。
用interface{}傳遞任意類型數據是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函數返回值
"_"標識符,用來忽略函數的某個返回值
Go 的返回值可以被命名,并且就像在函數體開頭聲明的變量那樣使用。
返回值的名稱應當具有一定的意義,可以作為文檔使用。
匿名函數
匿名函數是指不需要定義函數名的一種函數實現方式。
在Go里面,函數可以像普通變量一樣被傳遞或使用,Go語言支持隨時在代碼里定義匿名函數。
匿名函數由一個不帶函數名的函數聲明和函數體組成。匿名函數的優越性在于可以直接使用函數內的變量,不必申明。
package main
import (
"fmt"
"math"
)
func main() {
getSqrt := func(a float64) float64 {
return math.Sqrt(a)
}
fmt.Println(getSqrt(4))
}
// 返回
// 2
上面先定義了一個名為getSqrt 的變量,初始化該變量時和之前的變量初始化有些不同,使用了func,func是定義函數的,可是這個函數和上面說的函數最大不同就是沒有函數名,也就是匿名函數。這里將一個函數當做一個變量一樣的操作。
Golang匿名函數可賦值給變量,做為結構字段,或者在 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)()) } 輸出結果: Hello, World! 101 Hello, World! Hello, World! 閉包
閉包是由函數及其相關引用環境組合而成的實體(即:閉包=函數+引用環境)。
函數與閉包
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()
//輸出結果
//1
//2
//3
//a() //不會輸出i
//1
//2
//3
}
這段代碼有兩個特點:
函數b嵌套在函數a內部 函數a返回函數b 這樣在執行完var c=a()后,變量c實際上是指向了函數b(),再執行函數c()后就會顯示i的值,第一次為1,第二次為2,第三次為3,以此類推。 其實,這段代碼就創建了一個閉包。因為函數a()外的變量c引用了函數a()內的函數b(),就是說:
當函數a()的內部函數b()被函數a()外的一個變量引用的時候,就創建了一個閉包。 在上面的例子中,由于閉包的存在使得函數a()返回后,a中的i始終存在,這樣每次執行c(),i都是自加1后的值。 從上面可以看出閉包的作用就是在a()執行完并返回后,閉包使得go的垃圾回收機制GC不會收回a()所占用的資源,因為a()的內部函數b()的執行需要依賴a()中的變量i。
在給定函數被多次調用的過程中,這些私有變量能夠保持其持久性。變量的作用域僅限于包含它們的函數,因此無法從其它程序代碼部分進行訪問。不過,變量的生存期是可以很長,在一次函數調用期間所創建所生成的值在下次函數調用時仍然存在。正因為這一特點,閉包可以用來完成信息隱藏,并進而應用于需要狀態表達的某些編程范型中。
下面來想象另一種情況,如果a()返回的不是函數b(),情況就完全不同了。因為a()執行完后,b()沒有被返回給a()的外界,只是被a()所引用,而此時a()也只會被b()引 用,因此函數a()和b()互相引用但又不被外界打擾(被外界引用),函數a和b就會被GC回收。所以直接調用a();是頁面并沒有信息輸出。
下面來說閉包的另一要素引用環境。c()跟c2()引用的是不同的環境,在調用i++時修改的不是同一個i,因此兩次的輸出都是1。函數a()每進入一次,就形成了一個新的環境,對應的閉包中,函數都是同一個函數,環境卻是引用不同的環境。這和c()和c()的調用順序都是無關的。
遞歸函數
遞歸,就是在運行的過程中調用自己。 一個函數調用自己,就叫做遞歸函數。
構成遞歸需具備的條件:
1.子問題須與原始問題為同樣的事,且更為簡單。
2.不能無限制地調用本身,須有個出口,化簡為非遞歸狀況處理。
斐波那契數列(Fibonacci)
這個數列從第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)) } } 輸出結果: 0 1 1 2 3 5 8 13 21 34
到此,關于“Go語言中函數、閉包和遞歸是什么意思”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。