一、核心特性
Go语言有一些让人影响深刻的核心特性核心特性,比如:以消息传递模式的并发、独特的_符号、defer 、函数和方法、值传递等等,可以查看这篇文章《Go语言-让我印象深刻的13个特性》。首先要记住一些核心特性的用法。

1.Goroutine
- 协程:独立的栈空间,共享堆空间,比线程更轻量。
- 线程:一个线程上可以跑多个协程。
- Go语言独有的协程,让程序员非常方便的使用并发编程,从而保留更多的心智去思考业务和创新。笔者认为这一点是Go语言最大的特性。
Goroutine就是这种协程特性的实现。Goroutine 是通过通信来共享内存,而不是共享内存来通信。通过共享内存来控制并发,会使编程变得更复杂,容易引入更多的问题。
Goroutine是由Go的运行时调度和管理。Go程序会智能地将 Goroutine 中的任务合理地分配给每个CPU,它在语言层面已经内置了调度和上下文切换的机制,不需要程序员去操作各种方法实现调度。
在Go语言中,当需要让某个任务并发执行时,只需要把这个任务包装成一个函数,开启一个Goroutine去执行就可以了。如下,只需要在调用函数时,在前面加上go关键字。
| func hello_go() { |
| fmt.Println("hello go!!!") |
| } |
| |
| func main() { |
| go hello_go() |
| fmt.Println("main done!!!") |
| time.Sleep(time.Second) |
| } |
2.接口
在Go语言中接口interface是一种类型。Go语言的接口比较松散,只要是实现了接口定义的方法,就是实现了这个接口,无需使用implement等关键字去声明。
定义接口:
| |
| type Sayer interface { |
| say() |
| } |
| |
| type dog struct { |
| } |
| type cat struct { |
| } |
| |
| func (d dog) say() { |
| fmt.Println("狗叫") |
| } |
| func (c cat) say() { |
| fmt.Println("猫叫") |
| } |
空接口可以存储任意类型:
| |
| var obj = map[string]interface{} |
使用类型断言判断空接口中的值:
| func main() { |
| var x interface{} |
| x = 123 |
| |
| v, ok := x.(string) |
| if ok { |
| fmt.Println(v) |
| } else { |
| fmt.Println("类型断言失败") |
| } |
| } |
接口特性:
- 接口类型变量能够存储所有实现了该接口的实例。 如下,Sayer类型的变量能够存储dog和cat类型的变量。
| |
| type Sayer interface { |
| say() |
| } |
| |
| type dog struct { |
| } |
| type cat struct { |
| } |
| |
| func (d dog) say() { |
| fmt.Println("狗叫") |
| } |
| func (c cat) say() { |
| fmt.Println("猫叫") |
| } |
| |
| func main(t *testing.T) { |
| var x Sayer |
| c := cat{} |
| d := dog{} |
| x = c |
| x.say() |
| x = d |
| x.say() |
| } |
| |
| type Sayer interface { |
| say() |
| } |
| type Mover interface { |
| move() |
| } |
| |
| |
| type dog struct { |
| } |
| |
| |
| func (d dog) say() { |
| fmt.Println("狗叫") |
| } |
| func (d dog) move() { |
| fmt.Println("狗移动") |
| } |
| |
| func main(t *testing.T) { |
| var x Sayer |
| var y Mover |
| |
| var d = dog{} |
| x = d |
| y = d |
| |
| x.say() |
| y.move() |
| } |
- 使用值接收者实现接口 和 使用指针接收者实现接口 有什么区别?值接受者实现时 可以用 指针类型赋值过去,但 指针接受者实现时 无法用 值类型赋值过去。
| |
| type Mover interface { |
| move() |
| } |
| type Sayer interface { |
| say() |
| } |
| |
| |
| type dog struct { |
| } |
| |
| |
| func (d *dog) say() { |
| fmt.Println("狗叫") |
| } |
| func (d dog) move() { |
| fmt.Println("狗移动") |
| } |
| |
| func TestProgram(t *testing.T) { |
| var x Sayer |
| var y Mover |
| |
| |
| var d = &dog{} |
| x = d |
| y = d |
| |
| x.say() |
| y.move() |
| } |
3.下划线
_是特殊标识符,用来忽略结果。
| buf := make([]byte, 1024) |
| f, _ := os.Open("/Users/***/Desktop/text.txt") |
4.Go语言中的指针
- &:用于获取变量的地址,其实就是所谓的指针类型**(地址类型)
- :用于获取指针所指向的值*

| func main() { |
| a := 10 |
| fmt.Printf("type of a: %Tn", a) |
| b := &a // 取变量a的地址,将指针保存到b中 |
| fmt.Printf("type of b: %Tn", b) |
| c := *b // 取出 指针b 所指向的值 |
| fmt.Printf("type of c: %Tn", c) |
| fmt.Printf("value of c: %vn", c) |
| } |
5.new和make的区别
- 二者都是用来做内存分配的。
- make只用于slice、map、channel的初始化,返回的还是这三个引用类型本身。这里的引用有别于指针,他是对 slice、map、channel 值的间接访问,并不是一个指向 slice、map、channel 的指针。
- new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。指针是一个变量,存储了值的内存地址。
6.defer延迟调用
关键字 defer 用于注册延迟调用。这些调用直到 return 前才被执。可以用来做资源清理,常用来关闭资源。defer 是先进后出。
| func main() { |
| arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} |
| for _, v := range arr { |
| defer fmt.Println("循环:", v) |
| } |
| fmt.Println("主流程跑完") |
| time.Sleep(time.Second * 3) |
| |
| } |
二、常用类型和内置函数
1.常用类型
| bool |
| int, int8, int16, int32, int64 |
| uint, uint8, uint16, uint32, uint64 |
| float32, float64 |
| string |
| complex64, complex128 |
| array |
| struct |
| string |
| slice |
| map |
| chan |
| interface // 接口 或 任意类型 |
| func // 函数 |
2.常用内置函数
| append |
| copy |
| len |
| cap |
| delete |
| panic |
| recover |
| make |
| new |
| close |
三、变量、常量
| |
| var name string |
| |
| |
| const pi = 3.1415 |
| const e = 2.7182 |
| |
| const ( |
| pi = 3.1415 |
| e = 2.7182 |
| ) |
| |
| |
| n := 10 |
四、数据结构
1.数组
数组的长度固定:
| var arr1 = [5]int{1, 2, 3, 4, 5} |
| |
| arr2 := [...]struct { |
| name string |
| age int8 |
| }{ |
| {"yangling", 1}, |
| {"baily", 2}, |
| } |
2.切片
切片的长度不固定:
| |
| var s1 []int |
| s2 := []int{} |
| var s3 = make([]int, 0) |
| |
| |
| s1 = append(s1, 2, 3, 4) |
| |
| |
| s1[low:high] |
| |
| |
| for index, element := range s1 { |
| fmt.Println("索引:", index, ",元素:", element) |
| } |
3.Map
| scoreMap := make(map[string]int) |
| scoreMap["张三"] = 90 |
| scoreMap["李四"] = 100 |
| |
| userInfo := map[string]string{ |
| "username": "baily", |
| "password": "111111", |
| } |
| |
| |
| |
| v, ok := scoreMap["李四"] |
| if ok { |
| fmt.Println(v) |
| } else { |
| fmt.Println("查无此人") |
| } |
| |
| |
| for k, v := range scoreMap { |
| fmt.Println(k, v) |
| } |
| |
| |
| delete(scoreMap, "王五") |
4.结构体
不同的使用方式,可能返回指针,也可能返回值。
| |
| type Student struct { |
| name string |
| age int |
| } |
| |
| func main() { |
| |
| |
| |
| var stu1 Student |
| stu1.name = "baily" |
| stu1.age = 1 |
| fmt.Println("baily1:", stu1) |
| |
| |
| var stu2 = Student{ |
| name: "baily", |
| age: 1, |
| } |
| fmt.Println("baily2:", stu2) |
| |
| |
| stu3 := &Student{ |
| name: "baily", |
| age: 1, |
| } |
| fmt.Println("baily3指针:", stu3) |
| fmt.Println("baily3值:", *stu3) |
| |
| |
| var stu4 = new(Student) |
| stu4.name = "baily" |
| stu4.age = 1 |
| fmt.Println("baily4指针:", stu4) |
| fmt.Println("baily4值:", *stu4) |
| |
| } |
五、流程控制
流程控制包括:if、switch、for、range、select、goto、continue、break。主要记下select,其他的跟别的语言类似。主要用于等待资源、阻塞等待等等。
select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
| func main() { |
| var c1 = make(chan int) |
| go func() { |
| time.Sleep(time.Second * 10) |
| c1 |