GO語言學習筆記(三)流控制、函數

流控制

golang精簡了控制語句,但足夠我們使用。

if...else 語句需要注意一點的是對初始化語句的支持。

	if x := xtest(); x == 0 {  // 先執行xtest函數,再對x==0條件表示式判斷布爾值
		fmt.Println(x)
	}

switch...case語句同樣對初始化語句支持,此外不能出現重複的cacs值,單個case支持多條件匹配。

package main

import "fmt"

func xtest(x int) {
	switch y := x + 1; y {
	case 1, 2, 3: // 當x滿足其中一項時即匹配
		fmt.Println("1|2|3")
	case 4:
		fmt.Println("4")
	case 5: // 該語句等同於case5 : break
	default:
		fmt.Println("Unkown")
	}
}

func main() {
	xtest(2)
	xtest(3)
	xtest(4)
}

switch可以省略條件表達式,默認爲true。

package main

import "fmt"

func xtest(x int) {
	switch {  // 等同於 switch true
	case x > 0:
		fmt.Println("Positive", x)
	case x < 0:
		fmt.Println("Nagetive", x)
	default:
		fmt.Println("Zero", x)
	}
}

func main() {
	xtest(0)
	xtest(1)
	xtest(-1)
}

需要注意的是switch的條件表達式如果未false時,case匹配規則剛好相反,爲不滿足case的條件表達式時匹配。

package main

import "fmt"

func xtest(x int) {
	switch false {
	case x >= 0:
		fmt.Println("Positive", x)
	case x <= 0:
		fmt.Println("Nagetive", x)
	default:
		fmt.Println("Zero", x)
	}
}

func main() {
	xtest(0)
	xtest(1)
	xtest(-1)
}

switch..case語句無需顯示執行break語句,case執行完畢後自動跳出,如果需要繼續執行下一個的case,可使用fallthrough,但不再匹配後續case條件表達式。fallthrough必須放在case塊結尾.。

package main

import "fmt"

func xtest(x int) {
	switch {
	case x > 0:
		fmt.Println("Positive", x)
		fallthrough
	case x < 0:
		fmt.Println("Nagetive", x)
		fallthrough
	default:
		fmt.Println("Zero", x)
	}
}

func main() {
	xtest(3)
}

golang中循環語句只有for一種,但是for的條件表達式有多種形式。

package main

import "fmt"

func main() {

	for i := 0; i < 2; i++ { // 常用方式
		fmt.Println("i=", i)
	}

	j := 0
	for j < 2 { // 相當於 for _; j< 2; _
		fmt.Println("j=", j)
		j++
	}

	for { // 相當於for true
		break
	}

	i := []string{"hello", "world"}
	for k, s := range i { // 遍歷s切片,k可以替換成_
		fmt.Println(k, s)
	}

}

函數

golang函數使用func定義函數,需要注意幾點特性

1)函數無需前置聲明

2)函數不支持嵌套定義

3)函數不支持重載

4)函數支持不定參數

5)函數支持多返回值

6)函數支持命名返回值

7)函數支持匿名函數和閉包

函數定義包括函數名、參數列表、返回值列表(可省略)和函數體。

func name(parameter list)(rusult list){
    body
}

函數在golang中作爲第一對象,可以作爲參數、返回值、變量。相同返回值列表和參數列表的函數被認作一種數據類型。

package main

import "fmt"

type priInt func(int) int

func a(x int) int {
	fmt.Println("Func a", x)
	x++
	return x
}

func b(x int) int {
	fmt.Println("Func b", x)
	return x
}

func test(x priInt) priInt {
	x(1)
	return x
}

func main() {
	var funtest priInt
	funtest = test(a)
	funtest(2)
	funtest = test(b)
	funtest(2)
}

golang函數的參數列表支持相鄰同類型合併,golang函數參數列表支持不定長參數,本質上不定長參數是切片。切片必須放在參數列表尾部。

package main

import "fmt"

func test(x, y int, a ...string) {
	fmt.Println(x, y, a)
}

func main() {
	test(1, 2, "hello", "abc")
}

golang函數支持多返回值,並且函數支持命名返回值,即返回值變量作爲局部變量使用方式和參數一致。

package main

import "fmt"

func test1() (int, int, int) { // 多返回值函
	return 1, 2, 3
}

func test2() (x int, y string) {
	x = 1
	y = "hello"
	return // 隱式轉化 相當於 return x, y
}

func main() {
	a, b, _ := test1() // 多餘不需要的返回值可使用_替換
	fmt.Println(a, b)

	c, d := test2()
	fmt.Println(c, d)
}

golang函數支持匿名函數,與正常函數相比,減去了函數名稱。匿名函數常用在函數內部嵌套上,匿名函數可以賦值給變量,或者作爲參數、返回值。

package main

import "fmt"

func test(a func(int)) func(string) { // 匿名函數作爲參數和返回值
	a(1)
	return func(str string) {
		fmt.Println(str)
	}
}

func main() {
	func() {
		fmt.Println("hello")
	}() //聲明匿名函數並直接調用

	a := func() {
		fmt.Println("world")
	} //聲明匿名函數並賦值給變量
	a()
	b := test(func(i int) {
		fmt.Println("abc")
	})

	b("123")
}

Golang函數支持閉包特性,閉包指的是函數在使用中引用了函數上下文的環境。閉包會使上下文環境聲明週期變長,如果上下文中定義了局部變量,該變量將被分配到堆中。

package main

import "fmt"

func test() func() {
	x := 1
	fmt.Println(x, &x)
	return func() {
		fmt.Println(x, &x) // 匿名函數引用了上下文變量x
	}
}

func main() {
	a := test()
	a()
}

golang函數支持延時調用,當函數運行流程結束後,開始執行延時調用函數。使用defer可以向當前函數註冊演示調用函數,當函數註冊了多個延時調用函數,其執行順尋是後註冊的先執行。

package main

import "fmt"

func test() int { 
	x := 1
	defer func() {
		x++
		fmt.Println("defer", x)
	}()

	defer func() {
		x++
		fmt.Println("defer2", x) // 先執行
	}()

	return x // 執行完後開始執行延時調用
}

func main() {
	fmt.Println(test())
}

golang函數使用painc和recover實現類似try...catch的結構化異常捕捉。painc會立即終止當前函數流程,並執行當前函數延遲調用函數。

在延時調用函數中使用recover捕捉painc提交的錯誤對象。需要注意的是golang程序異常時,使用painc代表着程序終止。

package main

import (
	"fmt"
	"log"
)

func main() {
	defer func() {
		if err := recover(); err != nil { // 捕捉異常
			log.Fatalln(err)
		}
	}()

	panic("This is painc") // 終止函數流程

	fmt.Println("main") // 不會執行
}

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章