GO入门学习
Go语言环境配置(Linux下)
下载GO源代码
Google官方网站:https://golang.org/dl/
Go官方镜像:https://golang.google.cn/dl/
中文网站:https://studygolang.com/dl
安装GO源代码
tar -zxvf go.... -C /usr/local/
修改环境变量
vim ~/.bashrc
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
GOROOT表示源代码位置
GOPATH表示开发者GO的项目默认路径
source ~/.bashrc
go version
检查是否安装成功
go --help
检查是否安装成功
GO IDE
- Goland
- VScode
- Vim + Go 插件
Golang 概览
优势
极简单的部署方式
- 可直接编译机器码(编译速度可以超过C)
- 不依赖其它库
ldd 查看依赖
- 直接运行即可部署(运行速度慢于C/C++)
静态类型语言
- 编译时检查出来隐藏的大多数问题
语言层面的并发
- 天生的并发支持
- 充分利用多核(切换成本低 充分利用CPU)
package main
import (
"fmt"
"time"
)
func goFunc(i int) {
fmt.Printf("goroutine", i , "...")
}
func main() {
for i:= 0; i < 10000; i++ {
go goFunc(i) // 开启协程
}
time.Sleep(time.Second)
}
强大的标准库支撑
- runtime系统调度机制
- 高效的GC垃圾回收
- 丰富的标准库
- 加密解密
- 底层库
- 文本
- 输入输出
- 数学
- 压缩
- 测试
- 文件系统
- 进程、线程Goroutine
- 数据持久化与交换
- 网络通信
- 同步机制
- 应用构建
- 数据结构与算法
简单易学
- 25个关键字
- C语言简洁基因,内嵌C语法支持
- 面向对象特征(继承、多态、封装)
- 跨平台
大厂常用
- facebook(facebookgo)
- Tencent(蓝鲸)
- Baidu(BFE, 通讯消息, 百度云盘Go版本)
- 京东
- 小米、七牛(原生GO公司)、阿里巴巴、bilibili、ByteDance
使用领域
云计算基础设计领域
- Docker
- K8s
- etcd
- consul
- cloudflare CDN
- 七牛云存储
基础后端软件
- tidb
- infuxdb
- cockroachdb
微服务
- go-kit
- micro
- monzo bank的typhon
- bilibili
- tarsgo
互联网基础设施
- 以太坊
- hyperledger
缺点(不足)
包管理
大部分包都在Github上
无泛化类型
所有Exception都用Error来处理
没有try catch
对C的降级处理,并非无缝,没有C降级到ASM那么完美(序列化问题)
兼容C代码也只是通过Cgo来调用C的代码
Go基础
从main方法来了解go的语法规则
package main // 当前程序属于main包
/*
import "fmt"
import "time"
*/
import (
"fmt"
"time"
)
// main 函数
func main() { // 花括号只能是这种代码风格
fmt.Printf("Hello GO")
time.Sleep(1 * time.Second)
}
编译并执行:
go run hello.go
四种变量声明方式
// 声明全局变量 1 2 3 方法可以
var gA int = 100
var gB = 200
// 第四种方法声明全局变量 只能在函数体内部声明
//gC := 200
func Var() {
// 四种变量声明方法
// 1. 声明一个变量 默认值是0
var a int
fmt.Println(a)
// 2. 声明变量初始化
var b int = 100
fmt.Println(b)
// 3. 在初始化的时候,让编译器根据值来匹配类型
var c = 100
fmt.Printf("type of C = %T\n", c)
// 4. 常用的方法 省去var关键字 直接自动匹配
e := 100
fmt.Printf("type of e = %T\n", e)
// 声明多个变量
var x, y int = 100, 200
var xx, yy = 100, "xx"
var (
vv int = 100
jj bool = true
ss = "aaaa"
)
var emptyString string
fmt.Println(emptyString, x, y, xx, yy, vv, jj, ss)
}
常量与iota
package main
import (
"fmt"
)
// const 定义枚举属性
const (
// 可以在const添加关键字 iota, 每一行的iota都会累加1, 第一行默认是0
BEIJING = 10 * iota
SHANGHAI
SHENZHEN
)
const (
a, b = iota + 1, iota + 2 // iota = 0
c, d // iota = 1
e, f
g, h = iota * 2, iota * 3
)
// 枚举属性
func main() {
// 常量 只读
const length int = 10;
}
函数多返回值
func fool(a string, b string) int {
return 100
}
//匿名返回多个值
func fool2 (a string, b string) (int, int) {
return 100 ,2
}]
// 返回多个值带有形参名称 默认地址为0
func fool3(a string, b int) (r1 int, r2 int) {
r1 = 1000;
r2 = 2000;
return
}
func fool4 ()(r1, r2 int) {
r1 = 1
r2 = 2
return
}
func mian() {
c := fool ("aa", "bb")
a , b = fool2("aa", "bb")
ret1, ret2 = fool3("aa", 12)
}
Import导包路径与init方法调用
import(
"GolangStudy/5-inti/lib1" // 相对路径完成
)
import匿名及别名导包
import (
_ "GolangStudy..." // _为匿名 可能不使用
myLib "Lib" // 别名
. "MyLib" // MuLib包下的方法都是在本包下的
)
func main() {
muLib.test()
MyLibTest()
}
GO指针
package main
import "fmt"
func changeValue(p *int) {
*p = 10
}
func main() {
var a int = 1
changeValue(&a)
fmt.Println("a = ", a)
}
defer语句调用顺序
defer按照压栈的顺序来打印
func main() {
defer fmt.Println("main end1")
defer fmt.Println("main end2")
defer myFunc()
}
数组与动态数组的区别
func main() {
var MyArray [10]int // 默认0
var MyArray2 [10]int{1, 2, 3, 4} // 默认0
for idx, value range MyArray2 {
}
}
func print(myArray []int) {
// 引用传递
for _, value := range myArray {
}
}
func main() {
MyArray := []int {1, 2, 3, 4}// 默认0
}
四种slice切片声明定义方式
func main() {
// 声明初始长度为3的
slice1 := []int{1, 2, 3}
// 声明slice是一个切片 但是没有空间
var slice2 []int
slice2 = make([]int, 3) // make来开辟空间
slice2[0] = 100
//1 ,2 合二为一
var slice3 []int = make([]int, 3)
slice4 := make([]int, 3)
fmt("%d, %v", len(slice1), slice1) // %v 打印详细信息
}
slice切片追加与截取
追加
func main() {
var numbers = make([]int, 3, 5)
}
func main() {
var numbers = make([]int, 3, 5) // len = 3, cap = 5
numbers = append(numbers, 1) // 追加1 len = 4, cap = 5
}
超过之后采用初始化的cap * k进行 append
func main() {
var numbers = make([]int, 3) // len = 3 cap = 3
numbers = append(numbers, 1) // 追加1 len = 4, cap = 6
}
截取:浅拷贝
func main() {
numbers := []int{1, 2, 3}
s1 := s[0 :2]
}
深拷贝
func main() {
numbers := []int{1, 2, 3}
s1 := make([]int, 3)
copy(s1, numbers)
}
map三种声明方式
func main() {
// 1.声明myMap为map类型 key是int value 为string
var myMap map[int]string // 默认空map
myMap := make(map[int]string, 10) // 开辟十个空间
myMap[1] = "java" // hash表 所以是乱序
myMap[222] = "c++"
// 2. 第二种声明
myMap := make(map[int]string)
myMap[2] = "java"
//3. 第三正声明方式
myMap := make(map[string]string) {
"aa" : "java"
"sss" : "aaaa"
}
}
map的使用方式
func main() {
cityMap := make(map[string] string)
// 插入或修改
cityMap["china"] = "beijing"
cityMap["Jappen"] = "Tokyo"
//遍历
for key, value := range cityMap {
}
// 删除
delete(citMap, "china")
}
结构体
// typedef
type myint int
// 结构体
type Book struct {
title string
auth string
id int
}
func printBook(book Book) {
// 副本传递
fmt.Printf("%dv\n", book1)
}
func main() {
var book1 Book
book1.title = "Golang"
fmt.Printf("%dv\n", book1)
}
面向对象与类的封装
// 类就是结构体来访问方法 类名大写表示对其它包开放 否则内部访问
type Hero struct {
Name string
Ad int
level int // 内部访问 private
}
// this拷贝执行当前调用的对象
func (this Hero) GetName(){
fmt.Printf("name = %s", this.name)
}
// this * 指针可以修改
func (this *Hero) SetName(name string){
this.Name = name
}
func main() {
hero := Hero{Name : "zhang3", ad:100, level:1}
}
面向对象继承
type Human struct {
name string
sex string
}
func (this *Human) Eat() {
fmt.("Human Eat.")
}
func (this *Human) Walk() {
fmt.("Human walk.")
}
type SuperMan struct {
Human
level int
}
// 覆盖、重写父类方法
func (this *superMan) Eat() {
fmt.("Superman Eat.")
}
func main() {
h := Human{"zhang3", "female"}
h.Eat()
h.walk()
s := SuperMan{
Human{"li4", "femal"}
levle : 1
}
s.Walk() // 父类的方法
s.Eat() // 子类的方法
var s SuperMan
s.name = "li4"
s.sex = "male"
s.level = 88
}
多态的实现及基本要素
// 本质是一个指针 可以指向实现该接口的任意类
type Animal interface {
Sleep()
GetColor() string
GetType() string
}
type Cat struct {
color string
}
func (this *Cat) Sleep() {
fmt.Printl("Cat is Sleep")
}
func (this *Cat) GetColor() string{
return this.color
}
func (this *Cat) GetType() {
return "Cat"
}
type Dog struct {
color string
}
func (this *Dog) Sleep() {
fmt.Printl("Cat is Sleep")
}
func (this *Dog) GetColor() string{
return this.color
}
func (this *Dog) GetType() {
return "Cat"
}
func ShowAnimal(animal AnimalIF) {
animal.Sleep() // 多态实现
}
func main() {
var animal AnimalIF // 接口数据类型 指针
animal = &Cat{"Green"}
animal.Sleep()
}
空接口万能类型与类型断言机制
func myFunc(arg interface {}) {
fmt.Printf("myFunc")
fmt.Println(arg)
// 区分底层数据类型 -- 类型断言
value,ok = arg.(string) // 判断是否是string
if !ok {
// not string
} else {
// is string
}
}
func main() {
book := Book{"golang"}
myFunc(book)
myFunc(123)
}
内置pair结构
反射机制reflect包
ValueOf 返回pair中的value
TypeOf返回pair中的type
import(
"reflect"
)
// 基本用法
func reflectNum(arg interface{}) {
fmt.Println("type:", reflect.TypeOf(arg))
fmt.Println("type:", reflect.ValueOf(arg))
}
结构体标签
package main
type resume struct {
// 说明作用 有什么作用
Name string `info:"anme" doc:"我的名字"`
Sex string `info:"sex"`
}
func findTag(str interface{}) {
t := reflec.TypeOf(str)
for i := 0; i < t.NumFiled() {
tag := t.Filed(i).Tag.Get("info")
fmt.Printf(tag)
}
}
func main() {
}
结构体标签在json中的应用
import "encoding/json"
type Movie struct {
Title string `json:"title"` // 标签映射
Year int `json:year`
Price int `json:rmb`
Actors []string `son:actors`
}
func main() {
movie := Movie{"喜剧之王", 200, 10, []string{"xingye", "zhangbozhi"}}
// 编码过程:结构体 -> json
jsonStr, err := json.Marshal(movie)
if err != nil {
return
}
fmt.Println(jsonStr);
// 解码过程 jsonStr -> 结构体
myMovie := Movie{}
err = json.Unmarshal(jsonStr, &myMovie)
if err != nil {
return
}
}
创建goroutine
// 子goroutine
func newTask() {
i := 0
for {
i ++
fmt.Printf("new Goroutine")
time.Sleep(1 * time.Second)
}
}
// 主goroutine
func main() {
go newTask
i := 0
for {
i++
fmt.Printf("new Goroutine")
time.Sleep(1 * time.Second)
}
}
匿名函数
// 子goroutine
// 主goroutine
func main() {
go func() {
}
}
拿不到goroutine的返回值
Channel
无缓冲channel
有缓冲的channel
当通道被填满(或者为空)的时候就会阻塞掉。
channel的关闭特点
- 关闭后不能再发送,但是可以继续接收
- nil channel 无论收发都要被阻塞
channel与range
迭代查询c的range
channel与select
select 具备监听多路channel的监控状态
GoModules
GOPATH工作模式的弊端
- 没有版本控制概念
- 无法同步一致第三方版本号
- 无法指定当前项目引用的第三方版本号
GoModules初始化项目
-
开启go模式
go env -w GO111MODULE=on
-
创建新项目路径:新建任意文件夹
-
go mod 初始化工作
go mod init github.com/DengSchoo/module_test
-
下载依赖的包
go get github.com/
改变项目模块的版本依赖关系
项目一《Golang即时通讯系统》
架构图
版本迭代
- 版本一:构建基础Server
- 版本二:用户上线功能
- 版本三:用户消息广播机制
- 版本四:用户业务层封装
- 版本五:在线用户查询
- 版本六:修改用户名
- 版本七:超时强踢功能
- 版本八:私聊功能
- 版本九:客户端实现