1.数据类型
1.1基础数据类型
布尔型 bool
整型 int
浮点型flaot32/64
字符型 byte
字符串 string
1.数据类型1.1基础数据类型布尔型 bool 整型 int 浮点型flaot32/64 字符型 byte 字符串 string [code]//基础数据类型//定义一个布尔类型的变量avar a bool//定义一个int类型的变量bvar b int//float32类型var c float32//字符类型var d byte//字符串var e string |
1.2派生类型
指针类型(pointer)
数组类型
结构化类型(struct)
Channel 类型
函数类型
切片类型
接口类型(interface)
Map 类型
[code]//定义一个长度为2的string数组fvar f [2]string//定义一个切片g 切片类似于list的结构var g []int//定义一个结构体h 结构体类似于Java中的entity的概念 但是使用更加灵活type h struct { x string y int z float32}//定义一个Map i,示例中 string为map的key类型,int为map的value类型var i map[string[LL(1] ]int[LL(2] //指针类型 j是一个指向int值的指针var j *int [code]//定义一个main方法,main方法为一个项目的主方法func main() { [code]//定义并赋值l,使用 := ,l的类型为所赋值的类型 l:=1 [code]// &l代表指向l变量的内存地址 j=&l [code]// 在指针j前面加*用来获取指针j所指向的内容 m :=*j fmt.Print(j,m)[LL(3] } [code]// 创建一个传递string类型的信道n [code]var n chan string |
上述main函数运行结果如下
0xc00000a0c8 1 |
Interface和channel使用在后面单独章节
2.流程控制
2.1 for
类似于其他语言,for循环有三种形式,Break 关键字可以用于跳出循环
[code]//for 初始化条件; 循环控制条件; 赋值表达式 {循环体}for i := 0; i < 5; i++[LL(4] { fmt.Println(i)} [code] m := 5n := 0//for 循环控制条件{循环体}for n < m { n++ fmt.Println(n)}//for range 用于遍历数组,切片,map 格式如下// for index/key,value :=range slice/map/数组 {fmt.Print(index/key,value)}x := []int{1, 2, 1, 5, 10}for y, z := range x { fmt.Printf(\"第 %d 位 x 的值 = %d\\n\", y, z)}
|
运行结果如下
//第一个for循环运行结果 0 1 2 3 4 //第二个for循环运行结果 1 2 3 4 5 //第三个for循环运行结果 第 0 位 x 的值 = 1 第 1 位 x 的值 = 2 第 2 位 x 的值 = 1 第 3 位 x 的值 = 5 第 4 位 x 的值 = 10 |
2.2 if
[code]m := 5n := 0//if 布尔表达式{ [code]表达式为true时执行的语句 [code]//}else{ else必须和if结束的大括号同一行 [code]}if n < m { fmt.Println(n)}else{ fmt.Println(m)}
|
If语句可以嵌套
2.3 swich
[code]grade := \"\"marks := 90switch marks {case 90[LL(5] : grade = \"A\"case 80: grade = \"B\"case 50, 60, 70: grade = \"C\" [code]//default表示如果没有匹配到case 则执行default内表达式default: grade = \"D\"}fmt.Print(grade) |
3.函数与方法
3.1函数与方法的定义
在很多语言中,函数和方法指的是同一种东西。但是在Go语言中有所区别
在 Go 语言中有一个概念和函数极其相似,叫做方法 。Go 语言的方法其实是作用在接收者(receiver)上的一个函数,接收者是某种非内置类型的变量。因此方法是一种特殊类型的函数。
[code]//定义一个结构体student [code]type student struct { Id int Name string}//定义一个函数getName() 返回值类型为stringfunc getName[LL(6] (stu student) string { [code] fmt.Println(\"函数被调用\") return stu.Name}//定义一个方法 getNamefunc (stu student) getName() string { [code] fmt.Println(\"方法被调用\") return stu.Name}
|
3.2函数和方法的调用
函数将变量作为参数:Function1(recv)
方法在变量上被调用:recv.Method1()
[code]func main() { a := student{ Id: 12, Name: \"Any\", }[LL(7] [code]//调用getName()函数 getName(a) [code]//调用getName()方法 a.getName()}
|
运行结果如下
函数被调用 方法被调用 |
4.接口
4.1定义一个接口
Go 语言并没有类和继承的概念。但是 Go 语言里有非常灵活的接口概念,通过它可以实现很多面向对象的特性。接口定义了一组方法集合,但是这些方法不包含具体的实现代码,接口定义中不能包含变量。
[code]//使用interface关键字定义接口,Phone为接口名,call()为接口中定义的方法 [code]type Phone interface { call() //message()} |
4.2实现接口
实现一个接口需要实现接口中的所有方法。
[code]type Nokia struct { name string model string}type Iphone struct { name string color string}//func (nokia Nokia)call() { fmt.Printf(\"nokia call ! %v ,%v\",nokia.name,nokia.model)}func (iphone Iphone)call() { fmt.Printf(\"iPhone call! %v,%v\",iphone.name,iphone.color)}
|
4.3使用接口
[code]func main() { /* var phone Phone phone = Nokia{ name: \"机皇\", model: \"N97\", } fmt.Println(reflect.TypeOf(phone)) phone.call()*/ phone := Nokia{ name: \"机皇\", model: \"N97\", } phone.call() iphone := Iphone{ name: \"5s\", color: \"rich gold\", } iphone.call()}
|
4.4接口嵌套
接口可以嵌套,子接口拥有父接口所有方法,使用子接口时,需要实现父接口和子接口中所有的方法。
[code]type Phone interface { Call Message}type Call interface { answer()}type Message interface { sendMessage() receiceMessage()}
|
4.5空接口
Go语言空接口(interface{})不包含任何的method,所有的类型都实现了空interface,空interface可以存储任意类型的数值。[LL(8]
[code]slice := make([]interface{}, 10)map1 := make(map[string]string)map2 := make(map[string]int)map2[\"TaskID\"] = 1map1[\"Command\"] = \"ping\"map3 := make(map[string]map[string]string)map3[\"mapvalue\"] = map1slice[0] = map2slice[1] = map1slice[3] = map3fmt.Println(slice[0])fmt.Println(slice[1])fmt.Println(slice[3]) |
5.反射[LL(9]
反射需要用到reflect包
5.1利用反射获取数据类型和值
reflect.ValueOf()用于获取参数的值,获取的参数类型为空接口,可以获取所有类型的参数
reflect.TypeOf()用于获取参数的类型
[code]var circle float64 = 6.28[LL(10] fmt.Println(\"Reflect : circle.Value = \", reflect.ValueOf(circle))fmt.Println(\"Reflect : circle.Type = \", reflect.TypeOf(circle))
|
5.2用反射进行变量修改
[code]var circle float64 = 6.28//CanSet()函数确认变量是否是可修改的value := reflect.ValueOf(circle)fmt.Println(\"Reflect : value = \", value)fmt.Println(\"Settability of value : \", value.CanSet())//value2表示指向circle的指针value2 := reflect.ValueOf(&circle)fmt.Println(\"Settability of value : \", value2.CanSet())//value3是表示circle的指针的反射 reflect.Elem() 获取这个指针指向的元素类型value3 := value2.Elem()fmt.Println(\"Settability of value : \", value3.CanSet())//修改circle的指针的反射类型的值value3.SetFloat(3.14)fmt.Println(\"Value of value3: \", value3)fmt.Println(\"value of circle: \", circle)
|
6.并发
6.1 goroutine(协程)
在Go中,应用程序并发处理的部分被称作 goroutines(go协程),它可以进行更有效的并发运算。在协程和操作系统线程之间并无一对一的关系:协程是根据一个或多个线程的可用性,映射(多路复用,执行于)在它们之上的;协程调度器在 Go 运行时很好的完成了这个工作。
Go 程序中使用 go 关键字为一个函数创建一个 goroutine。一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。
[code]func main() { [code]//创建一个loop方法的协程 go loop() loop()}func loop() { for i := 0; i < 10; i++ { fmt.Printf(\"%d \", i) }} |
6.2 channel(信道)
Channel是Go中的一个核心类型,可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯。
它的操作符是箭头 <-
[code]var x boolc := make(chan bool) //创建一个无缓冲的bool型Channelc <- x //向一个Channel发送一个值x<- c //从一个Channel中接收一个值x = <- c //从Channel c接收一个值并将其存储到x中x, ok = <- c //从Channel接收一个值,如果channel关闭了或没有数据,那么ok将被置为false |
信道在取消息和存消息的时候都会挂起当前的goroutine,除非另一端已经准备好。如果不用信道来阻塞主线的话,主线程就会过早跑完,loop线程都没有机会执行。
[code]var complete := make(chan int)[LL(11] func loop() { for i := 0; i < 10; i++ { fmt.Printf(\"%d \", i) } complete <- 0 // 执行完毕了,发出消息}func main() { go loop() <-complete // 直到线程跑完, 取到消息. main在此阻塞住}
|
7.错误和异常处理
7.1 error(错误)
一般情况下,如果函数需要返回错误,就将 error 作为多个返回值中的最后一个(但并非是强制要求)。
[code]func Sqrt(f float64) (float64, error) { if f < 0 { return -1, errors.New(\"参数必须不小于0\") } [code]// 执行开方计算 return math.Sqrt(f) , nil}func main(){ result, err:= Sqrt(-2) if err != nil { fmt.Println(err) }else{ fmt.Println(result) }}
|
7.2 panic(异常)
错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中 ;而异常指的是不应该出现问题的地方出现了问题,比如引用了空指针,这种情况在人们的意料之外。错误是业务过程的一部分,而异常不是 。
[code]func main() { fmt.Println(\"Starting the program\") panic(\"A severe error occurred: stopping the program!\") fmt.Println(\"Ending the program\")} |
recover是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入panic,调用recover可以捕获到panic的输入值,并且恢复正常的执行。[LL(12]
可以使用关键字defer向函数注册退出调用,即主调函数退出时,defer后的函数才会被调用。
defer语句的作用是不管程序是否出现异常,均在函数退出时自动执行相关代码(类似于Java中的finally)。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。
[code]func badCall() { panic(\"bad end\")}func test() { defer func() { if e := recover(); e != nil { fmt.Printf(\"Panicing %s\\n\", e) } }() badCall() fmt.Printf(\"After bad call\\n\")}func main() { fmt.Printf(\"Calling test\\n\") test() fmt.Printf(\"Test completed\\n\")}
|
[LL(1]string为map的key类型
[LL(2]int为map的value类型
[LL(3]使用Print函数日志输出
[LL(4]Go语言中自增i++不是一个操作符而是语句,所以i=i++会导致编译错误,不存在++i,–也一样
[LL(5]case 90 [LL(5]表示marks==90是否成立,若结果为true则执行下面的 grade = \”A\”,若不成立则执行下一个case
[LL(6]在同一个package下允许函数和方法同名,但不允许函数之间同名。
Go语言中允许方法同名,但不允许同名方法同参,类似于Java中方法重载的概念
[LL(7]声明一个结构体变量a
[LL(8]类似于Java中的Object。
[LL(9]反射机制也类似于Java,其中reflect包功能类似于.Class
[LL(10]这里是我们已经定义的一个值,但是反射机制可以让我们获取空接口传来的任意参数的类型和值
[LL(11]创建一个无缓冲的int型 channel
[LL(12]类似于Java中的try catch模块
1.2派生类型
指针类型(pointer)
数组类型
结构化类型(struct)
Channel 类型
函数类型
切片类型
接口类型(interface)
Map 类型
[code]//定义一个长度为2的string数组fvar f [2]string//定义一个切片g 切片类似于list的结构var g []int//定义一个结构体h 结构体类似于Java中的entity的概念 但是使用更加灵活type h struct { x string y int z float32}//定义一个Map i,示例中 string为map的key类型,int为map的value类型var i map[string[LL(1] ]int[LL(2] //指针类型 j是一个指向int值的指针var j *int [code]//定义一个main方法,main方法为一个项目的主方法func main() { [code]//定义并赋值l,使用 := ,l的类型为所赋值的类型 l:=1 [code]// &l代表指向l变量的内存地址 j=&l [code]// 在指针j前面加*用来获取指针j所指向的内容 m :=*j fmt.Print(j,m)[LL(3] } [code]// 创建一个传递string类型的信道n [code]var n chan string |
上述main函数运行结果如下
0xc00000a0c8 1 |
Interface和channel使用在后面单独章节
2.流程控制
2.1 for
类似于其他语言,for循环有三种形式,Break 关键字可以用于跳出循环
[code]//for 初始化条件; 循环控制条件; 赋值表达式 {循环体}for i := 0; i < 5; i++[LL(4] { fmt.Println(i)} [code] m := 5n := 0//for 循环控制条件{循环体}for n < m { n++ fmt.Println(n)}//for range 用于遍历数组,切片,map 格式如下// for index/key,value :=range slice/map/数组 {fmt.Print(index/key,value)}x := []int{1, 2, 1, 5, 10}for y, z := range x { fmt.Printf(\"第 %d 位 x 的值 = %d\\n\", y, z)}
|
运行结果如下
//第一个for循环运行结果 0 1 2 3 4 //第二个for循环运行结果 1 2 3 4 5 //第三个for循环运行结果 第 0 位 x 的值 = 1 第 1 位 x 的值 = 2 第 2 位 x 的值 = 1 第 3 位 x 的值 = 5 第 4 位 x 的值 = 10 |
2.2 if
[code]m := 5n := 0//if 布尔表达式{ [code]表达式为true时执行的语句 [code]//}else{ else必须和if结束的大括号同一行 [code]}if n < m { fmt.Println(n)}else{ fmt.Println(m)}
|
If语句可以嵌套
2.3 swich
[code]grade := \"\"marks := 90switch marks {case 90[LL(5] : grade = \"A\"case 80: grade = \"B\"case 50, 60, 70: grade = \"C\" [code]//default表示如果没有匹配到case 则执行default内表达式default: grade = \"D\"}fmt.Print(grade) |
3.函数与方法
3.1函数与方法的定义
在很多语言中,函数和方法指的是同一种东西。但是在Go语言中有所区别
在 Go 语言中有一个概念和函数极其相似,叫做方法 。Go 语言的方法其实是作用在接收者(receiver)上的一个函数,接收者是某种非内置类型的变量。因此方法是一种特殊类型的函数。
[code]//定义一个结构体student [code]type student struct { Id int Name string}//定义一个函数getName() 返回值类型为stringfunc getName[LL(6] (stu student) string { [code] fmt.Println(\"函数被调用\") return stu.Name}//定义一个方法 getNamefunc (stu student) getName() string { [code] fmt.Println(\"方法被调用\") return stu.Name}
|
3.2函数和方法的调用
函数将变量作为参数:Function1(recv)
方法在变量上被调用:recv.Method1()
[code]func main() { a := student{ Id: 12, Name: \"Any\", }[LL(7] [code]//调用getName()函数 getName(a) [code]//调用getName()方法 a.getName()}
|
运行结果如下
函数被调用 方法被调用 |
4.接口
4.1定义一个接口
Go 语言并没有类和继承的概念。但是 Go 语言里有非常灵活的接口概念,通过它可以实现很多面向对象的特性。接口定义了一组方法集合,但是这些方法不包含具体的实现代码,接口定义中不能包含变量。
[code]//使用interface关键字定义接口,Phone为接口名,call()为接口中定义的方法 [code]type Phone interface { call() //message()} |
4.2实现接口
实现一个接口需要实现接口中的所有方法。
[code]type Nokia struct { name string model string}type Iphone struct { name string color string}//func (nokia Nokia)call() { fmt.Printf(\"nokia call ! %v ,%v\",nokia.name,nokia.model)}func (iphone Iphone)call() { fmt.Printf(\"iPhone call! %v,%v\",iphone.name,iphone.color)}
|
4.3使用接口
[code]func main() { /* var phone Phone phone = Nokia{ name: \"机皇\", model: \"N97\", } fmt.Println(reflect.TypeOf(phone)) phone.call()*/ phone := Nokia{ name: \"机皇\", model: \"N97\", } phone.call() iphone := Iphone{ name: \"5s\", color: \"rich gold\", } iphone.call()}
|
4.4接口嵌套
接口可以嵌套,子接口拥有父接口所有方法,使用子接口时,需要实现父接口和子接口中所有的方法。
[code]type Phone interface { Call Message}type Call interface { answer()}type Message interface { sendMessage() receiceMessage()}
|
4.5空接口
Go语言空接口(interface{})不包含任何的method,所有的类型都实现了空interface,空interface可以存储任意类型的数值。[LL(8]
[code]slice := make([]interface{}, 10)map1 := make(map[string]string)map2 := make(map[string]int)map2[\"TaskID\"] = 1map1[\"Command\"] = \"ping\"map3 := make(map[string]map[string]string)map3[\"mapvalue\"] = map1slice[0] = map2slice[1] = map1slice[3] = map3fmt.Println(slice[0])fmt.Println(slice[1])fmt.Println(slice[3]) |
5.反射[LL(9]
反射需要用到reflect包
5.1利用反射获取数据类型和值
reflect.ValueOf()用于获取参数的值,获取的参数类型为空接口,可以获取所有类型的参数
reflect.TypeOf()用于获取参数的类型
[code]var circle float64 = 6.28[LL(10] fmt.Println(\"Reflect : circle.Value = \", reflect.ValueOf(circle))fmt.Println(\"Reflect : circle.Type = \", reflect.TypeOf(circle))
|
5.2用反射进行变量修改
[code]var circle float64 = 6.28//CanSet()函数确认变量是否是可修改的value := reflect.ValueOf(circle)fmt.Println(\"Reflect : value = \", value)fmt.Println(\"Settability of value : \", value.CanSet())//value2表示指向circle的指针value2 := reflect.ValueOf(&circle)fmt.Println(\"Settability of value : \", value2.CanSet())//value3是表示circle的指针的反射 reflect.Elem() 获取这个指针指向的元素类型value3 := value2.Elem()fmt.Println(\"Settability of value : \", value3.CanSet())//修改circle的指针的反射类型的值value3.SetFloat(3.14)fmt.Println(\"Value of value3: \", value3)fmt.Println(\"value of circle: \", circle)
|
6.并发
6.1 goroutine(协程)
在Go中,应用程序并发处理的部分被称作 goroutines(go协程),它可以进行更有效的并发运算。在协程和操作系统线程之间并无一对一的关系:协程是根据一个或多个线程的可用性,映射(多路复用,执行于)在它们之上的;协程调度器在 Go 运行时很好的完成了这个工作。
Go 程序中使用 go 关键字为一个函数创建一个 goroutine。一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。
[code]func main() { [code]//创建一个loop方法的协程 go loop() loop()}func loop() { for i := 0; i < 10; i++ { fmt.Printf(\"%d \", i) }} |
Main()程序入口 |
go running()
running() running()
主程序执行完毕
6.2 channel(信道)
Channel是Go中的一个核心类型,可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯。
它的操作符是箭头 <-
[code]var x boolc := make(chan bool) //创建一个无缓冲的bool型Channelc <- x //向一个Channel发送一个值x<- c //从一个Channel中接收一个值x = <- c //从Channel c接收一个值并将其存储到x中x, ok = <- c //从Channel接收一个值,如果channel关闭了或没有数据,那么ok将被置为false |
信道在取消息和存消息的时候都会挂起当前的goroutine,除非另一端已经准备好。如果不用信道来阻塞主线的话,主线程就会过早跑完,loop线程都没有机会执行。
[code]var complete := make(chan int)[LL(11] func loop() { for i := 0; i < 10; i++ { fmt.Printf(\"%d \", i) } complete <- 0 // 执行完毕了,发出消息}func main() { go loop() <-complete // 直到线程跑完, 取到消息. main在此阻塞住}
|
7.错误和异常处理
7.1 error(错误)
一般情况下,如果函数需要返回错误,就将 error 作为多个返回值中的最后一个(但并非是强制要求)。
[code]func Sqrt(f float64) (float64, error) { if f < 0 { return -1, errors.New(\"参数必须不小于0\") } [code]// 执行开方计算 return math.Sqrt(f) , nil}func main(){ result, err:= Sqrt(-2) if err != nil { fmt.Println(err) }else{ fmt.Println(result) }}
|
7.2 panic(异常)
错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中 ;而异常指的是不应该出现问题的地方出现了问题,比如引用了空指针,这种情况在人们的意料之外。错误是业务过程的一部分,而异常不是 。
[code]func main() { fmt.Println(\"Starting the program\") panic(\"A severe error occurred: stopping the program!\") fmt.Println(\"Ending the program\")} |
recover是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入panic,调用recover可以捕获到panic的输入值,并且恢复正常的执行。[LL(12]
可以使用关键字defer向函数注册退出调用,即主调函数退出时,defer后的函数才会被调用。
defer语句的作用是不管程序是否出现异常,均在函数退出时自动执行相关代码(类似于Java中的finally)。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。
[code]func badCall() { panic(\"bad end\")}func test() { defer func() { if e := recover(); e != nil { fmt.Printf(\"Panicing %s\\n\", e) } }() badCall() fmt.Printf(\"After bad call\\n\")}func main() { fmt.Printf(\"Calling test\\n\") test() fmt.Printf(\"Test completed\\n\")}
|
[LL(1]string为map的key类型
[LL(2]int为map的value类型
[LL(3]使用Print函数日志输出
[LL(4]Go语言中自增i++不是一个操作符而是语句,所以i=i++会导致编译错误,不存在++i,–也一样
[LL(5]case 90 [LL(5]表示marks==90是否成立,若结果为true则执行下面的 grade = \”A\”,若不成立则执行下一个case
[LL(6]在同一个package下允许函数和方法同名,但不允许函数之间同名。
Go语言中允许方法同名,但不允许同名方法同参,类似于Java中方法重载的概念
[LL(7]声明一个结构体变量a
[LL(8]类似于Java中的Object。
[LL(9]反射机制也类似于Java,其中reflect包功能类似于.Class
[LL(10]这里是我们已经定义的一个值,但是反射机制可以让我们获取空接口传来的任意参数的类型和值
[LL(11]创建一个无缓冲的int型 channel
[LL(12]类似于Java中的try catch模块