语句

if

var a = 1

if a > 0 {
	fmt.Println("a>0")
} else if a == 0 {
	fmt.Println("a==0")
} else {
	fmt.Println("a<0")
}


//在条件中可以声明赋值,但不能用var,只能用:=,声明的变量的作用域是当前if语句中
if b := 1; b > 0 {
	fmt.Println("b>0")
} else if b == 0 {
	fmt.Println("b==0")
} else {
	fmt.Println("b<0")
}

 

switch

func f1(a, b int, operator string) {
	switch operator {
	case "+":
		fmt.Printf("%d%s%d=%d\n", a, operator, b, a+b)
	case "-":
		fmt.Printf("%d%s%d=%d\n", a, operator, b, a-b)
	case "*":
		fmt.Printf("%d%s%d=%d\n", a, operator, b, a*b)
	case "/":
		fmt.Printf("%d%s%d=%d\n", a, operator, b, a/b)
	default:
		//panic(fmt.Sprintf("不支持的运算符:%s", operator))
		panic("不支持的运算符:" + operator)
	}
}


func f2(score int) {
	switch {
	case score >= 80 && score <= 100:
		fmt.Println("优秀")
	case score >= 60 && score < 80:
		fmt.Println("良好")
	case score >= 0 && score < 60:
		fmt.Println("不及格")
	default:
		//panic(fmt.Sprintf("不合法的分数值:%d", score))
		panic("不合法的分数值:" + strconv.Itoa(score))
	}
}
  • case会自动加上break,不用手动加
  • switch后可以有表达式,也可以没有
  • case中可以写条件,可以写多个条件,作用类似于if语句

 

for

for i := 0; i < 10; i++ {
	fmt.Println(i)
}


arr := []string{"a", "b", "c", "d"}

//遍历数组,有2个变量时,第一个是下标,第二个是元素值
for index, value := range arr {
	fmt.Println(index, value)
}

//如果不使用其中某个变量,可写成_
for _, value := range arr {
	fmt.Println(value)
}

//如果只有一个变量,则为下标
for index := range arr {
	fmt.Println(index)
}


//初始值、循环条件、变量变化表达式均可缺省,全部缺省时为无限循环
for {
	fmt.Println("ok")
}
  • golang中没有while循环,while循环可以转换为for,使用for即可
  • 内建容器都可以用for range遍历

 

函数

函数的定义、使用

  • golang的参数、变量声明都是变量名在前,类型在后
  • golang函数的返回值类型放在最后,形参没有默认值
//无返回值时不用写返回值类型
func f1(name string, age int) {
	fmt.Printf("执行f1,name=%s,age=%d\n", name, age)
}


//如果参数类型相同,可以合写成 参数名1,参数名2 类型
func f2(a, b int, operator string) int {
	switch operator {
	case "+":
		return a + b
	case "-":
		return a - b
	case "*":
		return a * b
	case "/":
		return a / b
	default:
		panic("不支持的运算符:" + operator)
	}
}


//可以有多个返回值,返回值类型放在()中
func f3(a, b int) (int, int) {
	return b, a
}


func main() {
	f1("chy", 20)

	result := f2(10, 20, "+")
	fmt.Printf("f2()返回的值:%d\n", result)

	a, b := f3(10, 20)
	fmt.Printf("f3()返回的值:%d\t%d\n", a, b)
}

 

返回值名称

/*
可以给返回值起名字,这样Ctrl+ALt+V补全时会使用对应的变量名来接收
不建议这样做,到处都是变量名,看起来有些混乱,如果要用,尽量只用在简单的函数上
*/
func f1(a, b int) (sum, diff int) {
	return a + b, a - b
}

func main() {
	sum, diff := f1(100, 10)
	fmt.Println(sum, diff)
}

 

参数个数可变的函数

//参数个数可变的函数,使用数组接受参数
func sum(values ...int) int {
	sum := 0
	for _, value := range values {
		sum += value
	}
	return sum
}

func main() {
	sum := sum(1, 2, 3, 4)
	fmt.Println(sum)
}

 

函数作为参数

//函数可以作为参数。此处oper代表函数名,func(int, int) int是函数原型
func apply(oper func(int, int) int, a, b int) int {
	return oper(a, b)
}

func main() {
	result := apply(func(a int, b int) int {
		return a + b
	}, 10, 20)
	fmt.Println(result)
}

 

函数闭包

闭包:返回值是函数,返回函数中使用的局部变量也会保存在内存中

//func(int) int是函数原型,返回值类型是这种类型的函数
func adder() func(int) int {
	sum := 0
	//返回的函数中包含了变量sum,sum随返回的函数一起被保存在内存中
	return func(a int) int {
		sum += a
		return sum
	}
}

func main() {
	//用一个变量保存addr()返回的函数,可以把f做函数名来调用返回的函数
	f := adder()
	for i := 1; i < 10; i++ {
		fmt.Printf("0+...+%d=%d\n", i, f(i))
	}
}
  • i=1时,第一次调用f(i),sum=0+1=1,sum=1随函数被保存在内存中
  • i=2时,第二次调用f(i),sum=1+2=3 ,sum使用的是被保存在内存中的值,不是初始值

 

可见性规则

与其它语言的标识符命名规则不同,golang的标识命名有特殊含义,标识着可见性,不能随便大小写。

如果常量名、变量名、结构体名、函数名等

  • 以小写开头,则只在当前包中可见,可在当前中直接使用
  • 以大写开头,则是公共变量,在其它包中可见,可导入使用
     

假设有一个目录D:/gopath/demo,GOPATH是D:/gopath,demo是项目根目录,demo下有2个包:package1、main
 
package1

var Name = "chy"

func F() {
	fmt.Println("正在执行F()...")
}

//内部字段名也要大写,不然不能访问、操作内部字段
type Node struct {
	Value     int
	Pre, Next *Node
}

 
main

import (
	"fmt"
	//导入时取GOPATH后面的路径,直到包名
	"demo/package1"
)

func main() {
	//通过包名来引用
	fmt.Println(package1.Name)
	package1.F()

	head := package1.Node{Value: 10}
	fmt.Println(head.Value)
	fmt.Println(head.Pre)
}

导包时会先将import中的包的相对路径拼接在GOROOT后面,看存不存在,如果不存在,再拼接到GOPATH后面,看存不存在。

官方推荐把所有的golang项目、第三方库都放在GOPATH的src目录下。