源文件

原文件使用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}