环境搭建
-
下载go(https://studygolang.com/dl),配置环境变量,cmd输go验证
-
下载vscode(https://code.visualstudio.com/),并移至/Applications
介绍
优势
- 编译成机器码,不依赖其他库,直接运行即部署
- 静态类型语言,编译期检查出隐藏的大多数问题
- 语言层面并发,充分利用多核
- 强大的标准库,runtime系统调度机制,高效GC,丰富的标准库
- 简单,25个关键字,C语言简洁基因,面向对象,跨OS平台
- 性能,编译运行速度堪比C语言
不足
- 包管理,大部分在GitHub上
- 无泛型
- 无Exception,都是Error
- 不能完全兼容C,C是可以直接写ASM且完全兼容
Hello Go
hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
VSCode方式
// go.mod文件不存在问题解决
go env -w GO111MODULE=on
go mod init hello
// 下载包超时问题,安装方式Help -> Show All Commands -> Go:Install/Update
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
语法
init方法
lib.go
package lib
import "fmt"
// 小写开头,包内可访问,外包不可访问
func init() {
fmt.Println("init...")
}
// 大写开头,包内外都可访问
func Test() {
fmt.Println("test...")
}
指针
package main
import "fmt"
func swap(a *int, b *int) {
var t int = *a
*a = *b
*b = t
}
func main() {
var a, b int = 1, 2
swap(&a, &b)
fmt.Printf("a = %d, b = %d\n", a, b)
}
defer
defer函数在return之后调用,多个defer执行顺序是弹栈顺序
数组与切片
长度固定
package main
import "fmt"
// 值传递
func printArr(arr [3]int) {
for i, v := range arr {
fmt.Printf("arr[%d]=%d\n", i, v)
}
arr[0] = 100
}
func main() {
var arr1 [2]int
arr2 := [3]int{1}
fmt.Printf("arr1 type=%T\n", arr1)
for i := 0; i < len(arr1); i++ {
fmt.Printf("arr1[%d]=%d\n", i, arr1[i])
}
fmt.Println("============================")
fmt.Printf("arr2 type=%T\n", arr2)
for i, v := range arr2 {
fmt.Printf("arr2[%d]=%d\n", i, v)
}
fmt.Println("============================")
printArr(arr2)
fmt.Println("============================")
for i, v := range arr2 {
fmt.Printf("arr2[%d]=%d\n", i, v)
}
}
长度不定(切片)
package main
import "fmt"
// 引用传递
func printArr(arr []int) {
for i, v := range arr {
fmt.Printf("arr[%d]=%d\n", i, v)
}
arr[0] = 100
}
func main() {
arr := []int{1, 2, 3}
fmt.Printf("arr type=%T\n", arr)
printArr(arr)
fmt.Println("============================")
for i, v := range arr {
fmt.Printf("arr[%d]=%d\n", i, v)
}
}
package main
import "fmt"
func main() {
var slice []int
fmt.Printf("len = %d, slice = %v\n", len(slice), slice)
if slice == nil {
fmt.Println("slice is nil")
}
// slice[0] = 1 // 越界
slice = make([]int, 3)
fmt.Printf("len = %d, slice = %v\n", len(slice), slice)
}
package main
import "fmt"
func main() {
var slice = make([]int, 3, 5)
fmt.Printf("len = %d, capacity = %d, slice = %v\n", len(slice), cap(slice), slice)
slice = append(slice, 4)
fmt.Printf("len = %d, capacity = %d, slice = %v\n", len(slice), cap(slice), slice)
slice = append(slice, 5)
fmt.Printf("len = %d, capacity = %d, slice = %v\n", len(slice), cap(slice), slice)
// 会扩容一倍
slice = append(slice, 6)
fmt.Printf("len = %d, capacity = %d, slice = %v\n", len(slice), cap(slice), slice)
// slice2和slice指针地址相同,修改slice2[0]等同于修改了slice[0]
slice2 := slice[:4]
slice2[0] = 100
fmt.Println(slice)
// copy
slice3 := make([]int, 3)
copy(slice3, slice)
fmt.Println(slice3)
}
map
package main
import (
"fmt"
)
// 引用传递
func printMap(m map[int]string) {
for k, v := range m {
fmt.Printf("%d -> %s\n", k, v)
}
}
func main() {
fmt.Println("-------------m-------------")
var m = map[int]string{}
fmt.Printf("len = %d, m = %v, type = %T\n", len(m), m, m)
m[1] = "a"
m[2] = "b"
fmt.Printf("len = %d, m = %v, type = %T\n", len(m), m, m)
fmt.Println("-------------m2-------------")
m2 := map[int]string{
1: "aa",
2: "bb",
3: "cc",
}
printMap(m2)
fmt.Println("-------------m3-------------")
m3 := make(map[int]string, 6)
m3[1] = "aaa"
m3[2] = "bbb"
printMap(m3)
fmt.Println("-------------m3-------------")
delete(m3, 1)
printMap(m3)
}
struct
package main
import (
"fmt"
)
type Student struct {
id int
name string
score int
}
// 引用传递
func addScore(stu *Student, add int) {
stu.score += add
}
// 值传递
func addScore0(stu Student, add int) {
stu.score += add
}
func main() {
fmt.Println("---------stu---------")
var stu = &Student{
id: 1,
name: "Tom",
score: 90,
}
fmt.Printf("stu = %v\n", stu)
addScore(stu, 5)
fmt.Printf("stu = %v\n", stu)
fmt.Println("---------stu2---------")
var stu2 Student
stu2.id = 2
stu2.name = "Jack"
stu2.score = 92
fmt.Printf("stu2 = %v\n", stu2)
addScore0(stu2, 5) // 值传递
// addScore(&stu2, 5) // 引用传递
fmt.Printf("stu2 = %v\n", stu2)
}
面向对象
封装
package main
import (
"fmt"
)
type Account struct {
id int
name string
}
func (ac *Account) Show() {
fmt.Printf("[Account]{id:%d, name=%s}\n", ac.id, ac.name)
}
// 引用传递
func (ac *Account) SetName(name string) {
ac.name = name
}
func main() {
fmt.Println("---------Account---------")
ac := Account{id: 999, name: "Ahha"}
ac.Show()
ac.SetName("ahhA")
ac.Show()
}
继承
package main
import (
"fmt"
)
type Person struct {
id int
name string
}
type Student struct {
Person
score int
}
func (person *Person) Eat() {
fmt.Printf("Person.Eat\n")
}
func (stu *Student) Eat() {
fmt.Printf("Student.Eat\n")
}
func (stu *Student) Score() {
fmt.Printf("Student.Score\n")
}
func main() {
stu := Student{
Person: Person{id: 999, name: "abc"},
score: 90,
}
stu.Eat()
stu.Person.Eat()
stu.Score()
}
多态
package main
import (
"fmt"
)
// 本身已是指针
type Animal interface {
Sleep()
GetKind() string
}
type Cat struct {
kind string
}
func (cat *Cat) Sleep() {
fmt.Println("Cat is sleeping.")
}
func (cat *Cat) GetKind() string {
return "cat"
}
type Dog struct {
kind string
}
func (cat *Dog) Sleep() {
fmt.Println("Dog is sleeping.")
}
func (cat *Dog) GetKind() string {
return "dog"
}
func show(animal Animal) {
fmt.Printf("kind = %s\n", animal.GetKind())
animal.Sleep()
fmt.Println()
}
func main() {
var animal1 Animal = &Cat{kind: "cat"}
var animal2 Animal = &Dog{kind: "dog"}
show(animal1)
show(animal2)
}
interface{}
package main
import (
"fmt"
)
// interface{}是万能类型
func IsString(arg interface{}) {
fmt.Println("arg = ", arg)
value, ok := arg.(string) // 断言
if ok {
fmt.Println("arg is string type, value =", value)
} else {
fmt.Printf("arg is not string type, type = %T\n", arg)
}
fmt.Println()
}
func main() {
IsString(123)
IsString("xxx")
}
pair
package main
import "fmt"
func main() {
// 任何变量都内置pair<type, value>,赋给interface{}时,类型是确定的静态类型或具体类型
s := "123"
var anyType interface{} = s
if _, ok := anyType.(string); ok {
fmt.Println("s =", s)
}
}
反射
struct反射
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int `info:"id" doc:"unique id"`
Name string `info:"name" doc:"user name"`
Age int `info:"age"`
}
func (user User) Call() int {
fmt.Printf("user = %v", user)
return user.Id
}
func main() {
user := User{Id: 1, Name: "Tom", Age: 20}
Reflect(user)
ReflectTags(&user)
}
func Reflect(input interface{}) {
inputType := reflect.TypeOf(input)
fmt.Println("input type =", inputType.Name())
inputValue := reflect.ValueOf(input)
fmt.Println("input value =", inputValue)
for i := 0; i < inputType.NumField(); i++ {
field := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("%s: %s = %v\n", field.Name, field.Type, value)
}
for i := 0; i < inputType.NumMethod(); i++ {
method := inputType.Method(i)
fmt.Printf("%s: %v\n", method.Name, method.Type)
}
}
func ReflectTags(input interface{}) {
tags := reflect.TypeOf(input).Elem()
for i := 0; i < tags.NumField(); i++ {
tagInfo := tags.Field(i).Tag.Get("info")
tagDoc := tags.Field(i).Tag.Get("doc")
fmt.Println("tag info =", tagInfo, ", doc =", tagDoc)
}
}
struct标签在json中的应用
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
var err error
user := User{Id: 1, Name: "Tom", Age: 20}
// struct转json
jstr, err := json.Marshal(user)
if err != nil {
fmt.Println("json marshal error,", err)
} else {
// jstr = {"id":1,"name":"Tom","age":20}
fmt.Printf("jstr = %s\n", jstr)
}
user2 := User{}
// json转struct
err = json.Unmarshal(jstr, &user2)
if err != nil {
fmt.Println("json unmarshal error,", err)
} else {
// user = {1 Tom 20}
fmt.Println("user =", user2)
}
}
go routine
package main
import (
"fmt"
"time"
)
func main() {
go func() {
defer fmt.Println("A.defer")
func() {
defer fmt.Println("B.defer")
// runtime.Goexit() // 退出协程
fmt.Println("B")
}()
fmt.Println("A")
}()
for {
fmt.Println("main")
time.Sleep(3 * time.Second)
}
}
channel
协程通信
- 无缓冲,存等待对方取,取等待对方存
- 有缓冲,缓冲队列满了存才被阻塞,缓冲队列空了取才被阻塞
// 无缓冲
package main
import (
"fmt"
)
func main() {
c := make(chan int)
go func() {
c <- 999
}()
num := <-c // <-c 无空格
fmt.Println("num =", num)
}
// 有缓冲
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int, 3)
go func() {
defer fmt.Println("sub end")
for i := 0; i < 4; i++ {
c <- i
fmt.Println("sub running, i =", i, ", len =", len(c), ", capacity =", cap(c))
}
}()
time.Sleep(time.Second * 1)
for i := 0; i < 4; i++ {
num := <-c
fmt.Println("num =", num)
time.Sleep(time.Second * 1)
}
fmt.Println("main end")
}
关闭channel
package main
import (
"fmt"
)
func main() {
c := make(chan int)
go func() {
for i := 0; i < 3; i++ {
c <- i
}
close(c) // 若不关闭,会报死锁。fatal error: all goroutines are asleep - deadlock!
}()
// for data := range c {
// fmt.Println(data)
// }
for {
if data, ok := <-c; ok {
fmt.Println(data)
} else {
break
}
}
fmt.Println("main end")
}
go module
go path 不能进行版本控制,不能指定引入的第三方库的版本,所以引入了 go mod。引入第三方包后出现 go.sum 文件,校验和保证下载包是完整的,h1:哈希值(某包里所有文件一起的哈希值),go.mod h1:哈希值(某包下 mod 文件的哈希值)。
Reference
[1] https://golang.google.cn/
[2] go语言中文网
[3] 8小时转职Golang工程师
[4] Go语言后端开发如何规划学习路线?