上海市工程建設(shè)信息網(wǎng)官方網(wǎng)站廣東seo價(jià)格是多少錢
Go語(yǔ)言中的函數(shù)
go語(yǔ)言中函數(shù)特性
go語(yǔ)言有三種函數(shù):普通函數(shù)、匿名函數(shù)(沒(méi)有名稱的函數(shù))方法(定義在struct上的函數(shù))。receiver
go語(yǔ)言中不運(yùn)算函數(shù)重載(overload),也就是說(shuō)不允許函數(shù)同名
go語(yǔ)言中的函數(shù)不能嵌套,但是可以嵌套匿名函數(shù)
函數(shù)是一個(gè)值,可以將函數(shù)賦值給變量,使得這個(gè)變量也成為函數(shù)
函數(shù)可以作為參數(shù)傳遞給另一個(gè)函數(shù)
函數(shù)的返回值可以是另一個(gè)函數(shù)
函數(shù)調(diào)用的時(shí)候,如果有參數(shù)傳遞給函數(shù),則先拷貝參數(shù)的副本,再將副本傳遞給函數(shù)
函數(shù)參數(shù)可以沒(méi)有名稱
go語(yǔ)言中函數(shù)的定義和調(diào)用
函數(shù)在使用之前必須先定義,可以調(diào)用函數(shù)來(lái)完成某個(gè)任務(wù),函數(shù)可以重復(fù)調(diào)用,從而達(dá)到代碼的復(fù)用
func function_name([parameter_list])[return_types]{函數(shù)體
}

package mainimport "fmt"func sum(a int, b int) (res int) {res = a + breturn res
}
func main() {res := sum(1, 2)fmt.Printf("res: %v\n", res)
}
package mainimport "fmt"func compare(a int, b int) (max int) {if a > b {max = a} else {max = b}return max
}
func main() {res := compare(1, 2)fmt.Printf("res: %v\n", res)
}
go語(yǔ)言中的return
沒(méi)有返回值
有一個(gè)返回值 (例如上面的求和以及比較兩個(gè)數(shù)的大小的函數(shù))
存在多個(gè)返回值,且在return中指定返回的內(nèi)容
多個(gè)返回值,返回值名稱沒(méi)有被使用
return覆蓋命名返回值,返回值名稱沒(méi)有被使用
package mainimport "fmt"func test() {fmt.Print("testing...")
}
func main() {test()
}
package mainimport "fmt"func test() (string, int) {name := "Y4y17"age := 24return name, age
}
func main() {name, age := test()fmt.Printf("name: %v\n", name)fmt.Printf("age: %v\n", age)
}
package mainimport "fmt"func test() (name string, age int) {name = "Y4y17"age = 24return //相當(dāng)于return name,age
}
func main() {name, age := test()fmt.Printf("name: %v\n", name)fmt.Printf("age: %v\n", age)
}
package mainimport "fmt"func test() (name string, age int) {n := "Y4y17" //重新定義了n和a,那么返回的時(shí)候只能返回n和a,而不是name和agea := 24 //這種情況一般不這樣寫,一般就是直接去掉返回值中的name和age,只保留類型return n, a
}
func main() {name, age := test()fmt.Printf("name: %v\n", name)fmt.Printf("age: %v\n", age)
}
Go中經(jīng)常會(huì)使用其中一個(gè)返回值作為函數(shù)是否執(zhí)行成功、是否有錯(cuò)誤信息的判斷條件;例如return value,exists、return value,ok、return value,err等
當(dāng)函數(shù)的返回值過(guò)多的時(shí)候,例如有4個(gè)以上的返回值,應(yīng)該將這些返回值收集到容器中,然后以返回容器的方式去返回。例如,同類型的返回值可以放進(jìn)slice中,不同類型的返回值可以放進(jìn)map中。
當(dāng)函數(shù)有多個(gè)返回值的時(shí)候,如果其中某個(gè)或者是某幾個(gè)返回值不想用,可以通過(guò)下劃線_來(lái)丟棄這些返回值。
函數(shù)的參數(shù)
package mainimport "fmt"func test(a int) {a = 200 //test函數(shù)中修改變量a的值為200
}
func main() {a := 5 //定義變量a的值為5test(a)fmt.Printf("a: %v\n", a)//輸出a的值,依然還是5
}
數(shù)組、切片、指針都是傳地址,也就是傳址的方式;
package mainimport "fmt"func test(s []int) {s[2] = 17
}
func main() {s := []int{1, 2, 3, 4}test(s)fmt.Printf("s: %v\n", s)//輸出的結(jié)果為s: [1 2 17 4]
}
變長(zhǎng)參數(shù)
package mainimport "fmt"
//其實(shí)就像是傳遞了一個(gè)數(shù)組或者是切片
func test(args ...int) {for _, v := range args {fmt.Printf("v: %v\n", v)}
}
func main() {test(1, 2, 3, 4, 5, 6, 7)
}
package mainimport "fmt"func test(name string, b bool, args ...int) {fmt.Printf("name: %v\n", name)fmt.Printf("b: %v\n", b)for _, v := range args {fmt.Printf("v: %v\n", v)}
}
func main() {test("Y4y17", true, 1, 2, 3, 4, 5, 6, 7)
}
函數(shù)中的type關(guān)鍵字
相當(dāng)于在c語(yǔ)言中的typedef關(guān)鍵字,說(shuō)白了就是對(duì)現(xiàn)有的數(shù)據(jù)類型起了一個(gè)別名
package mainimport "fmt"func add(a int, b int) int {return a + b
}
func comp(a int, b int) int {if a > b {return a} else {return b}
}
func main() {type f func(a int, b int) intff := addr := ff(1, 2)fmt.Printf("r: %v\n", r)ff = compr = ff(1, 2)fmt.Printf("r: %v\n", r)
}
Go高階函數(shù)
函數(shù)作為參數(shù)
package mainimport "fmt"func test(name string, f func(string)) { f(name)
}
func sayHello(name string) {fmt.Printf("Hello: %v\n", name)
}
func main() {test("Y4y17", sayHello)
}
//test函數(shù)接受兩個(gè)參數(shù),分別是string類型的name和func(函數(shù)類型)的f(函數(shù)名)
sayHello函數(shù)接受一個(gè)參數(shù),即string類型的name,主函數(shù)中調(diào)用test函數(shù),傳遞參數(shù)Y4y17,和sayHello函數(shù)名;那么test函數(shù)中便會(huì)執(zhí)行sayHello("Y4y17")
函數(shù)作為返回值
package mainimport "fmt"func add(a int, b int) int {return a + b
}
func sub(a int, b int) int {return a - b
}
func test(operate string) func(int, int) int {//test函數(shù)接受一個(gè)string類型的參數(shù)operate,test函數(shù)返回值是一個(gè)函數(shù),該函數(shù)有兩個(gè)int類型的參數(shù)并且返回值也是int類型switch operate {case "+"://當(dāng)operate是+的時(shí)候,返回add方法return addcase "-"://當(dāng)operate是-的時(shí)候,返回sub方法return subdefault:return nil}
}func main() {f := test("-")res := f(1, 2)fmt.Printf("res: %v\n", res)
}
匿名函數(shù)
前面提到了在函數(shù)中是不允許嵌套函數(shù)的,但是我們可以使用匿名函數(shù),來(lái)實(shí)現(xiàn)一些簡(jiǎn)單的功能:
package mainimport "fmt"func main() {//匿名函數(shù)和普通函數(shù)的區(qū)別其實(shí)就是沒(méi)有了函數(shù)的名字,當(dāng)在一個(gè)函數(shù)中不寫函數(shù)名的時(shí)候就是匿名函數(shù)max := func(a int, b int) int {if a > b {return a} else {return b}}(1, 2) //直接在最后面加上()以及實(shí)參的時(shí)候,就是自己調(diào)用自己//r := max(3, 8) //fmt.Printf("r: %v\n", r)fmt.Printf("max: %v\n", max)
}
Golang閉包
閉包可以理解成定義在一個(gè)函數(shù)內(nèi)部的函數(shù)。在本質(zhì)上,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的橋梁,或者是說(shuō)函數(shù)和其引用環(huán)境的組合體
閉包指的是一個(gè)函數(shù)和與其相關(guān)的應(yīng)用環(huán)境組合而成的實(shí)體。簡(jiǎn)單來(lái)說(shuō),閉包=函數(shù)+引用環(huán)境。看下面的例子:
package mainimport "fmt"//定義一個(gè)函數(shù)名為test,該函數(shù)返回值是一個(gè)函數(shù),這個(gè)函數(shù)有一個(gè)int類型的參數(shù) 并且他返回值是一個(gè)int類型的數(shù)
func test() func(int) int {var x intreturn func(i int) int {x += ireturn x}
}
func main() {f := test()//f賦值為test的返回值,就是返回的函數(shù),初始x為0fmt.Printf("f(10): %v\n", f(10)) //計(jì)算0+10=>10 這里x就變成了10 而不是0fmt.Printf("f(20): %v\n", f(20)) //計(jì)算10+20=>30 這里x就變成了30 而不是10fmt.Printf("f(30): %v\n", f(30)) //計(jì)算30+30=>60 這里x就變成了60 而不是30
}
變量f是一個(gè)函數(shù)并且他引用了其外部作用域中的x變量,此時(shí)f就是一個(gè)閉包。在f的生命周期內(nèi),變量x也一直有效;
package mainimport ("fmt""strings"
)func makeSuffixFunc(suffic string) func(string) string {return func(name string) string {//這里的strings.HasSuff(name.suffic)表示判斷name是否以suffic結(jié)尾//如果是返回true,否則false 需要導(dǎo)包stringsif !strings.HasSuffix(name, suffic) {return name + suffic} else {return name}}
}
func main() {f := makeSuffixFunc("World")str := f("Hello")fmt.Printf("str: %v\n", str)
}
package mainimport "fmt"func cal(base int) (func(int) int, func(int) int) {add := func(a int) int {base += areturn base}sub := func(a int) int {base -= areturn base}return add, sub
}
func main() {add, sub := cal(10)res := add(10)fmt.Printf("res: %v\n", res)res = sub(5)fmt.Printf("res: %v\n", res)
}
定義了cal函數(shù),cal函數(shù)存在一個(gè)形參base,cal函數(shù)返回值存在兩個(gè),并且這兩個(gè)都是函數(shù),之后在cal函數(shù)中定義兩個(gè)匿名的函數(shù)分別賦值給add 和 sub,最終cal函數(shù)返回這兩個(gè)匿名函數(shù),之后在main函數(shù)中,令add sub為cal(10) ,其中base就是10 之后執(zhí)行res=add(10),而這個(gè)10是匿名函數(shù)的形參a=10,執(zhí)行base+=a故base=20
base的值會(huì)存儲(chǔ)下來(lái),之后res = sub(5),此時(shí)sub函數(shù)中的形參a就是5,再次執(zhí)行base-=a,故得到base=15
Go語(yǔ)言中的遞歸函數(shù)
函數(shù)內(nèi)部調(diào)用函數(shù)自身的函數(shù)稱之為遞歸函數(shù)
使用遞歸函數(shù)最重要的三點(diǎn):
遞歸就是自己調(diào)用自己
必須先定義函數(shù)的退出條件,沒(méi)有退出條件,遞歸將成為死循環(huán)
go語(yǔ)言遞歸函數(shù)很可能會(huì)產(chǎn)生一大堆的goroutine,也很可能會(huì)出現(xiàn)占空間內(nèi)存溢出的問(wèn)題
package mainimport "fmt"//數(shù)的階乘
func fc(n int) int {if n <= 1 {return 1} else {res := n * fc(n-1)return res}
}
func main() {res := fc(5)fmt.Printf("res: %v\n", res)
}
package mainimport "fmt"
//f(n)=f(n-1)+f(n-2) f(2)==f(1)==1
func fb(n int) int {if n <= 2 {return 1} else {res := fb(n-1) + fb(n-2)return res}
}
func main() {fmt.Printf("fb(3): %v\n", fb(3))
}
Go語(yǔ)言中的defer語(yǔ)句
go語(yǔ)言中的defer語(yǔ)句會(huì)將其后面跟隨的語(yǔ)句進(jìn)行延時(shí)處理,在defer歸屬的函數(shù)即將返回時(shí),姜堰市處理的語(yǔ)句按defer定義的逆序進(jìn)行執(zhí)行;也就是說(shuō)先被defer的語(yǔ)句最后被執(zhí)行,最后被defer的語(yǔ)句,最先被執(zhí)行
package mainimport "fmt"func main() {fmt.Printf("start...\n")defer fmt.Printf("stop1...\n")defer fmt.Printf("stop2...\n")defer fmt.Printf("stop3...\n")fmt.Printf("END...\n")
}
輸出結(jié)果如下:

Go語(yǔ)言中的init函數(shù)
golang有一個(gè)特殊的函數(shù)init函數(shù),先于main函數(shù)的執(zhí)行,主要實(shí)現(xiàn)包級(jí)別的一些初始化操作
init函數(shù)額主要特點(diǎn)
init函數(shù)先于main函數(shù)自動(dòng)執(zhí)行,不能被其他函數(shù)調(diào)用
init函數(shù)沒(méi)有輸入?yún)?shù)、返回值
每個(gè)包可以有多個(gè)init函數(shù)
包的每個(gè)源文件也可以有多個(gè)init函數(shù),這點(diǎn)比較特殊
同一個(gè)包的init執(zhí)行順序,golang沒(méi)有明確的定義;
不同包的init函數(shù)按照包導(dǎo)入的依賴關(guān)系決定執(zhí)行順序
初始化順序:變量初始化>init()>main()
package mainimport "fmt"var i int = initVar()func initVar() int {fmt.Printf("initvar...\n")return 100
}
func init() {fmt.Printf("init2...\n")
}
func init() {fmt.Printf("init...\n")
}
func main() {fmt.Printf("start...\n")
}
輸出結(jié)果為:

同時(shí)存在多個(gè)init()的時(shí)候,遵循自上而下的執(zhí)行順序