基本语法梳理
源文件
原文件使用UTF-8编码,对Unicode支持良好。每个源文件都属于包的一部分,在文件头部用package声明所属包的名称
1package main
2func main(){
3 println("hello world!!")
4}
以.go
作为文件扩展名,语句结束分号会被默认省略,支持C样式注释。入口函数main没有参数,且必须放在main包中
用import导入标准库或第三方包
1package main
2import{
3 "fmt"
4}
5
6func main(){
7 fmt.Println("hello world!")
8}
可以直接运行或者编译为可执行文件
变量
使用var定义变量,支持类型推断。基础数据类型划分清晰明确,有助于编写跨平台应用。编译器确保变量总是被初始化为0,避免出现意外状况。
1package main
2func main(){
3 var x int32
4 var s="hello world!"
5 // 两个数据之间默认使用空格隔开
6 println(x,s)
7}
在函数内部,还可以省略var关键字,使用更简单的定义模式。
1package main
2
3//y := 200 // 该声明方式仅在函数内部使用,不可用来声明全局变量
4func main() {
5 x := 100
6 println(x)
7}
编译器将未使用的局部变量定义当做错误
表达式
Go仅有三种流控制语句
if
1package main
2
3func main() {
4 x := 100
5 if x > 0 {
6 print("x")
7 } else if x < 0 {
8 print("-x")
9 } else {
10 print("0")
11 }
12}
switch
1package main
2
3func main() {
4 x := 0
5 switch {
6 case x > 0:
7 print("x")
8 case x < 0:
9 print("-x")
10 default:
11 print("0")
12 }
13}
for
1func main() {
2 for i := 0; i < 5; i++ {
3 println(i)
4 }
5 for i := 4; i >= 0; i-- {
6 println(i)
7 }
8}
1package main
2
3func main() {
4 x := 0
5 for x < 5 { // 相当于 while(x<5)
6 println(x)
7 x++
8 }
9}
1package main
2
3func main() {
4 x := 4
5 for { // 相当于while(true)
6 println(x)
7 x--
8 if x < 0 {
9 break
10 }
11 }
12}
在迭代遍历时,for…range除了元素外,还可以返回索引
1package main
2
3func main() {
4 x := []int{100, 101, 102}
5 for i, n := range x {
6 println(i, ": ", n)
7 }
8}
函数
多个返回值
函数可以定义多个返回值,甚至对其命名
1package main
2
3import (
4 "errors"
5 "fmt"
6)
7
8func main() {
9 a, b := 10, 0 // 定义多个变量
10 c, err := div(a, b) // 接收多个返回值
11 fmt.Println(c, err)
12}
13
14func div(a, b int) (int, error) {
15 if b == 0 {
16 return 0, errors.New("division by zero")
17 }
18
19 return a / b, nil
20}
返回函数
函数是第一类型,可以作为参数或者返回值
1package main
2
3func main() {
4 x := 100
5 f := test(x);
6 f()
7}
8
9func test(x int) func() { // 返回函数类型
10 return func() { // 匿名函数
11 println(x) // 闭包
12 }
13}
用defer定义延迟调用,无论函数是否出错,它都确保结束前被调用
1package main
2
3func main() {
4 test(10, 0)
5}
6
7func test(a, b int) {
8 defer println("dispose....") // 常用来释放资源、解除锁定、或执行一些清理操作
9 // 可以定义多个defer,按照FILO顺序执行
10 println(a / b)
11}
数据
切片 slice
切片(slice)可以实现类似动态数组的功能
1package main
2
3import "fmt"
4
5func main() {
6 x := make([]int, 0, 5) // 创建容量为5的切片
7 for i := 0; i < 8; i++ {
8 x = append(x, i) // 追加数据。当超出容量限制时候,自动分配更大的存储空间
9 }
10 fmt.Println(x)
11}
字典 map
字典(map) 类型内置,可以直接从运行层面获得性能优化
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[string]int) // 创建字典类型对象
7 m["a"] = 999 // 添加或设置
8 x, ok := m["a"] // 使用ok-idiom获取值,可知道key/value是否存在
9 fmt.Println(x, ok)
10 delete(m, "a") // 删除
11}
12
13// 999 true
14// 0 false
所谓 ok-idiom模式,是指在多返回值中用一个名为ok的布尔值来表示操作是否成功。因为很多操作默认返回零,所以额外说明
结构体
结构体(struct)可以匿名嵌入其他类型
1package main
2
3import "fmt"
4
5func main() {
6 var m manager
7 m.name = "Tom"
8 m.age = 29
9 m.title = "CTO" // 直接访问匿名字段成员
10
11 fmt.Println(m)
12}
13
14type user struct { // 结构体类型
15 name string
16 age byte
17}
18
19type manager struct {
20 user // 匿名嵌入其他类型
21 title string
22}
23
24// {{Tom 29} CTO}
方法
类型的方法
可以为当前包内的任意类型定义方法
1package main
2
3type X int
4
5func (x *X) inc() { // 名称前的参数称作receiver,作用类似Python self
6 *x++
7}
8
9func main() {
10 var x X
11 x.inc()
12 println(x)
13}
继承
还可以直接调用匿名字段的方法,这种方式可实现与继承类似的功能
1package main
2
3import "fmt"
4
5type user struct {
6 name string
7 age byte
8}
9
10func (u user) ToString() string {
11 return fmt.Sprintf("%+v", u)
12}
13
14type manager struct {
15 user
16 title string
17}
18
19func main() {
20 var m manager
21 m.name = "Tom"
22 m.age = 29
23 println(m.ToString()) // 调用user.ToString
24}
接口
结构采用了duck type
方式, 也就是无须在实现类型上添加显式声明
1package main
2
3import "fmt"
4
5type user struct {
6 name string
7 age byte
8}
9
10func (u user) Print() {
11 fmt.Printf("%+v\n", u)
12}
13
14type Printer interface { // 接口类型
15 Print()
16}
17
18func main() {
19 var u user
20 u.name = "Tom"
21 u.age = 29
22
23 var p Printer = u // 只要包含接口所需的全部方法,即表示实现了该接口
24 p.Print()
25}
另有空接口
类型interface{}, 用途类似OPP里的system.Object,可以接收任意类型的对象
并发
整个运行时完全并发设计。凡你能看到的,几乎都在以goroutine
方式运行。这是一种比普通协程或线程更加高效的并发设计,能轻松创建和运行成千上万的并发任务。
1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8func task(id int) {
9 for i := 0; i < 5; i++ {
10 fmt.Printf("%d: %d\n", id, i)
11 time.Sleep(time.Second)
12 }
13}
14
15func main() {
16 go task(1) // 创建 goroutine
17 go task(2)
18
19 time.Sleep(time.Second * 6)
20}
通道(channel) 与goroutine搭配,实现通信代替共享内存的CSP模型
1package main
2
3import "time"
4
5// 消费者
6func consumer(data chan int, done chan bool) {
7 for x := range data { // 接收数据,直到通道被关闭
8 println("recv: ", x)
9 }
10 done <- true // 通知main, 消费结束
11}
12
13// 生产者
14func producer(data chan int) {
15 for i := 0; i < 4; i++ {
16 data <- i // 发送数据
17 println("send: ",i)
18 time.Sleep(time.Second)
19 }
20 close(data) // 生产结束,关闭通道
21}
22
23func main() {
24 done := make(chan bool) // 用于接收消费结束信号
25 data := make(chan int) // 数据管道
26
27 go consumer(data, done) // 启动消费者
28 go producer(data) // 启动生产者
29
30 <-done // 阻塞,直到消费者发回结束信号
31}