函數(shù)
是執(zhí)行特定公開花颗、可復(fù)用的代碼塊,包括函數(shù)惠拭、匿名函數(shù)扩劝、閉包≈案ǎ可作為變量今野、返回值、參數(shù)等罐农。
func 函數(shù)名(參數(shù))(返回值){
函數(shù)體
}
函數(shù)名:字母条霜、數(shù)字、下劃線組成涵亏,第一個(gè)字母不能是數(shù)字宰睡;同一個(gè)包內(nèi)蒲凶,函數(shù)名也不能重名;
返回值:可返回多個(gè)返回值拆内,必須用()
包裹旋圆,并用,
分隔
函數(shù)定義與使用
func testOne(){
fmt.Println("Hello")
}
func testTwo(x int){
fmt.Println(x)
}
//多個(gè)同類型的參數(shù),可省略前面的類型
func testThree(x, y int){
fmt.Println(x, y)
}
func testSum(x int, y int)int{
ret := x + y
return ret
}
func testSum2(x int, y int)(ret int){
ret = x + y
return
}
//可變參數(shù)麸恍,在函數(shù)體中是切片類型
//固定參數(shù)和可變參數(shù)一起出現(xiàn)時(shí)候灵巧,可變參數(shù)必須放到最后
//go語言中沒有默認(rèn)參數(shù)
func testSum3(a int, x ...int)int{
fmt.Printf("tyep:%T,content:%v\n", a, a)
fmt.Printf("tyep:%T,content:%v\n", x, x)
sum := 0
for _, value := range x {
sum += value
// sum = testSum2(sum, value)
}
return sum
}
//多個(gè)返回值情況,必須用括號(hào)包起來
//多個(gè)返回值抹沪,也支持參數(shù)簡(jiǎn)寫
func calc(a, b int)(sum, sub int){
sum = a + b
sub = a - b
return
}
func main() {
testOne()
testTwo(2)
testThree(3, 3)
fmt.Println(testSum(1, 1))
fmt.Println(testSum2(2, 2))
sum1 := testSum3(1, 2, 3, 4, 5);
fmt.Println(sum1)
sum2 := testSum3(1, 2, 3, 4);
fmt.Println(sum2)
sum3 := testSum3(1);
fmt.Println(sum3)
sum, sub := calc(100, 200)
fmt.Println(sum, sub)
}
defer語句
將其后面跟隨的語句進(jìn)行延遲處理刻肄,在defer
歸屬的函數(shù)即將返回時(shí),將延遲處理的語句按照defer
定義的逆序進(jìn)行執(zhí)行(先被defer
的語句最后執(zhí)行融欧,最后被defer
語句敏弃,最先被執(zhí)行)。
defer語句非常方便處理資源釋放問題噪馏,比如資源清理麦到、文件關(guān)閉、解鎖及記錄時(shí)間等欠肾。
//defer 延遲執(zhí)行
func main() {
fmt.Println("start")
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
fmt.Println("end")
}
輸出
start
end
3
2
1
經(jīng)典案例
package main
import "fmt"
//1.匯編層面定義一個(gè)變量接收函數(shù)返回值
//2.return x瓶颠,則這個(gè)返回變量的值為5
//3.defer指令,x++刺桃,x為6
//4.匯編層面RET指令粹淋,返回變量的值是5
func f1() int {
x := 5
defer func(){
x++
}()
return x
}
//1.匯編層面定義一個(gè)變量接收函數(shù)返回值,是x
//2.return x虏肾,則這個(gè)返回變量的值為5廓啊,x=5
//3.defer指令,x++封豪,x=6
//4.匯編層面RET指令谴轮,返回變量的值是6(x=6)
func f2() (x int) {
defer func(){
x++
}()
return 5
}
//1.匯編層面定義一個(gè)變量接收函數(shù)返回值,是y
//2.return x吹埠,則這個(gè)返回變量的值為5第步,y=5
//3.defer指令,x++缘琅,x=6
//4.匯編層面RET指令粘都,返回變量的值是5(y=5)
func f3() (y int) {
x := 5
defer func(){
x++
}()
return x
}
//1.匯編層面定義一個(gè)變量接收函數(shù)返回值,是x
//2.return x刷袍,則這個(gè)返回變量的值為5翩隧,x=5
//3.defer指令,值傳遞
//4.匯編層面RET指令呻纹,返回變量的值是5(x=5)
func f4() (x int) {
defer func(x int){
x++
}(x)
return 5
}
func main() {
fmt.Println(f1()) //5
fmt.Println(f2()) //6
fmt.Println(f3()) //5
fmt.Println(f4()) //5
}
image.png
作用域
- 函數(shù)內(nèi)部可以訪問全局變量堆生,如果函數(shù)內(nèi)部定義同名的局部變量专缠,先取用局部變量;
- 外層不能訪問函數(shù)的內(nèi)部變量(局部變量)淑仆;
- 外層訪問不到內(nèi)部for涝婉、if、switch語句塊中的變量蔗怠;
//定義全局變量
var num = 10
func test(){
fmt.Println("全局變量", num)
num := 20
fmt.Println("局部變量", num)
}
func main() {
test()
fmt.Println("全局變量", num)
}
輸出
全局變量 10
局部變量 20
全局變量 10
函數(shù)作為變量
//定義全局變量
var num = 10
func test(){
fmt.Println("全局變量", num)
num := 20
fmt.Println("局部變量", num)
}
func main() {
//函數(shù)作為變量
abc := test
fmt.Printf("%T\n", abc)
//調(diào)用
abc()
}
輸出
func()
全局變量 10
局部變量 20
函數(shù)作為參數(shù)
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
func calc(x, y int, op func(int, int) int) int{
return op(x, y)
}
func main() {
add := calc(100, 200, add)
fmt.Println(add)
sub := calc(100, 200, sub)
fmt.Println(sub)
}
匿名函數(shù)
沒有函數(shù)名的函數(shù)
func(參數(shù))(返回值){
函數(shù)體
}
func main() {
//匿名函數(shù)賦值給變量
test := func(){
fmt.Println("haha")
}
test()
//匿名函數(shù)直接使用
func(){
fmt.Println("hihi")
}()
}
閉包
閉包
指的是一個(gè)函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體墩弯,即閉包=函數(shù)+引用環(huán)境
。
//函數(shù)返回值是函數(shù)
func a() func() {
name := "lv"
return func(){
fmt.Println("haha", name)
}
}
func b(name string) func() {
return func(){
fmt.Println("haha", name)
}
}
func main() {
//閉包 = 函數(shù) + 外層變量的引用
r := a()
r() //相當(dāng)于執(zhí)行了a函數(shù)內(nèi)部的匿名函數(shù)
c := b("c")
c()
}
常用內(nèi)置函數(shù)
內(nèi)置函數(shù) | 介紹 |
---|---|
close | 主要是用來關(guān)閉channel |
len | 求長度寞射,例如string渔工、array、slice怠惶、map涨缚、channel |
new | 主要分配值類型內(nèi)存轧粟,例如 int策治、struct、string兰吟、array等通惫,返回的是指針 |
make | 主要分配引用類型的內(nèi)存,比如chan混蔼、map履腋、slice |
append | 追加元素到array、slice中 |
panic和recover | 用來錯(cuò)誤處理 |
Go(1.12)沒有異常處理惭嚣,用panic
和recover
遵湖。panic
是運(yùn)行時(shí)候錯(cuò)誤。
recover
必須搭配defer
使用defer
一定要在可能引發(fā)panic
的語句之前定義
func a(){
fmt.Println("func a")
}
func b(){
defer func(){
err := recover()
if err != nil {
panic("func b error")
}
}()
panic("panic in b")
}
func c(){
fmt.Println("func c")
}
func main() {
a()
b() //程序崩潰
c()
}