Skip to content
On this page

流程控制

for循环

  • 循环语句中不用加()
  • for后面不跟随表达式等价于JavaScript中的while(true),此时语句中要有break/return,不然会无限循环
Go
package main

import "fmt"

func testFor() {
	k := 1
	for {
		if k > 3 {
			break
		}
		fmt.Println("k的值为:", k);
		k++
	}
}

func main() {
	testFor()
}
// 打印 
// k的值为: 1
// k的值为: 2
// k的值为: 3
  • for后面跟随一个表达式等价于JavaScript中的while(condation)
Go
package main

import "fmt"

func testFor() {
	i := 1
	for i <= 3 {
		fmt.Println("i的值为:", i)
		i++
	}
}

func main() {
	testFor()
}
// 打印 
// i的值为: 1
// i的值为: 2
// i的值为: 3
  • for后面跟随3个表达式等价于JavaScript中的for(初始化,判断,后续)
Go
package main

import "fmt"

func testFor() {
	for f := 1; f <= 3; f++ {
		fmt.Println("f的值为:", f)
	}
}

func main() {
	testFor()
}
// 打印 
// f的值为: 1
// f的值为: 2
// f的值为: 3

if else

  • if else语句中不推荐加()
  • if后面跟随一个表达式等价于JavaScript中的if(condition)
Go
package main

import "fmt"

func testIfElse() {
	i := 6
	if i > 5 {
		fmt.Println("i的值大于5,i为:", i)
	}
}

func main() {
	testIfElse()
}
// 打印 i的值大于5,i为: 6
  • if后面声明的变量,只能在if else语句中才能访问到,外面访问不到
Go
package main

import "fmt"

func testIfElse() {
	if f := 12; f >= 18 { // 相当于先声明一个变量f为12,再判断是否满足f>=18这个条件
		fmt.Println("大于等于18岁,成年了")
	} else if f > 10 {
		fmt.Println("大于10岁,小于18岁")
	} else {
		fmt.Println("不到10岁")
	}
	// fmt.Println(f) 在if后面声明的变量,外部是拿不到的,只有if else 语句能拿到
}

func main() {
	testIfElse()
}
// 打印 大于10岁,小于18岁

switch case

  • switch语句中不加()
  • case默认添加了break语句,不用手动写,如果希望当前case匹配到之后继续执行下一个case的代码,使用fallthrough
  • case后可以跟多个值
Go
package main

import (
	"fmt"
	"time"
)
func testSwitch() {
	switch time.Now().Weekday() {
		case time.Monday:
			fmt.Println("周一")
		case time.Tuesday:
			fmt.Println("周二")
		case time.Saturday, time.Sunday:
			fmt.Println("周末")
		default:
			fmt.Println("周三到周五")
	}
}

func main() {
	testSwitch()
}
// 打印 周二

添加了fallthrough

Go
package main

import (
	"fmt"
	"time"
)
func testSwitch() {
	switch time.Now().Weekday() {
		case time.Monday:
			fmt.Println("周一")
		case time.Tuesday:
			fmt.Println("周二")
      fallthrough
		case time.Saturday, time.Sunday:
			fmt.Println("周末")
		default:
			fmt.Println("周三到周五")
	}
}

func main() {
	testSwitch()
}
// 打印
// 周二
// 周末

defer 延迟调用

defer延迟调用函数

  • defer语句后面跟着的函数会延迟到当前函数执行完后再执行
Go
func deferFunc() {
	fmt.Println("hello")
	defer fmt.Println("defer后跟随的打印")
	fmt.Println("go go go")
}

func main() {
  // hello
  // go go go
  // defer后跟随的打印
	deferFunc()
}

值的修改对defer调用打印的影响

  • defer只是延时调用函数,传递给函数里的值类型的变量,不会受到后续程序的影响;

  • 引用类型的变量打印会跟随修改;

Go
func deferVaribale() {
	name := "张环"
	defer fmt.Println("defer打印的name", name)
	name = "李朗"
	fmt.Println("name修改后为", name)
	
	age := []int{22, 66, 88}
	defer fmt.Println("defer打印的age", age)
	age[1] = 99
	fmt.Println("更新后的age为", age)
}

func main() {
  // name修改后为 李朗
  // 更新后的age为 [22 99 88]
  // defer打印的age [22 99 88]
  // defer打印的name 张环
	deferVaribale()
}

延迟调用方法

  • defer不仅能够延迟函数的执行,也能延迟方法的执行;
Go
type Reader interface {
	read()
}
type Person struct {
	name	string
	like 	string
}
func (p Person) read() {
	fmt.Printf("%s喜欢%s\n", p.name, p.like)
}

func deferMethod() {
	person := Person {
		name: "张环",
		like: "读书",
	}
	defer person.read()
	fmt.Println("person 值为", person)
}

func main() {
  // person 值为 {张环 读书}
  // 张环喜欢读书
	deferMethod()
}

defer

  • 当一个函数内多次调用defer时,Go会把defer调用放入到一个中,随后按照先进后出的顺序执行。
Go
func deferStack() {
	fmt.Println("start")
	defer fmt.Println("第一个defer打印")
	defer fmt.Println("第二个defer打印")
	defer fmt.Println("第三个defer打印")
	defer fmt.Println("第四个defer打印")
	defer fmt.Println("第五个defer打印")
	defer fmt.Println("第六个defer打印")
	fmt.Println("end")
}

func main() {
	deferStack()
  // start
  // end
  // 第六个defer打印
  // 第五个defer打印
  // 第四个defer打印
  // 第三个defer打印
  // 第二个defer打印
  // 第一个defer打印
}

defer栈作用域

  • 当作用域为当前函数时,不同函数下有不同的defer
Go
func testDeferScope() {
	func (){
		defer fmt.Println("张环")
		defer fmt.Println("李朗")
		defer fmt.Println("沈韬")
	}()
	fmt.Println("-----------------")
	func (){
		defer fmt.Println(22)
		defer fmt.Println(66)
		defer fmt.Println(88)
	}()
	fmt.Println("=================")
}

func main() {
	testDeferScope()
	// 打印
	// 沈韬
	// 李朗
	// 张环
	// -----------------
	// 88
	// 66
	// 22
	// =================
}

deferreturn函数使用匿名返回值

Go
var str string = "张环"

func deferVal() string {
	defer func(){
		str = "李朗"
	}()
	fmt.Println("deferVal 函数内部的 str", str)
	return str
}

func main() {
	str_val := deferVal();
	fmt.Println("deferVal函数返回值str_val", str_val)
	fmt.Println("deferVal函数外部的str", str)
	// 打印如下
	// deferVal 函数内部的 str 张环
	// deferVal函数返回值str_val 张环
	// deferVal函数外部的str 李朗
}

deferreturn函数使用命名返回值

Go
func testDeferReturn() (num int) {
	num = 10
	defer func(){
		num += 5
	}()
	return 2
}

func main() {
	num := testDeferReturn()
	fmt.Println(num) // 7
}
  • 首先变量num作为返回值,初始值为0

  • 其次,变量num被赋值为10

  • 然后return时,变量num被重新赋值为2

  • deferreturn后执行,拿到变量num将其修改为7

  • 最终函数返回结果为7

defer遇到panic

  • painc时,已经声明的defer会出栈执行,在panic之后声明的defer将不会执行
Go
func testDeferPanic() {
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	panic("------------")
	defer fmt.Println(5) // 在panic之后声明的defer 将不会执行
}

func main() {
	testDeferPanic()
	// 打印
	// 3
	// 2
	// 1
	// panic: ------------
	// 程序崩溃,没有打印5
}

使用recover捕获panic

Go
func testCatchPanic() {
	defer func (){
		if err := recover(); err != nil {
			fmt.Println( "程序崩溃原因:", err)
		}
	}()
	panic("来,崩溃吧")
}

func main() {
	testCatchPanic()
  // 打印 程序崩溃原因: 来,崩溃吧
}

goto无条件跳转

  • Go语言中保留gotogoto后面接的是标签,表示下一步要执行哪里的代码
Go
goto label_name
...
label_name: code

示例

Go
func baseGoTo() {
	fmt.Println("start goto")
	goto skip
	fmt.Println("中间打印")
	skip: fmt.Println("直接调转到这里")
}

func main() {
	baseGoTo()
	// 打印
	// start goto
	// 直接调转到这里
}
  • goto语句与标签之间不能有变量声明
Go
func testDefineVariable() {
	fmt.Println("start goto")
	goto define
	fmt.Println("中间打印")
	name := "sdf"
	fmt.Println(name)
	define: fmt.Println("直接调转到这里")	
}

func main() {
  // 运行报错 goto define jumps over declaration of name
	testDefineVariable()
}