Go
大约 5 分钟
Go
介绍
- 2019年开始了解Go语言,到现在慢慢补。
- 本文档介绍了Go语言基础
描述
- 学习项目: go-study
官网
安装提示
下载完后打开运行-> Next -> 按默认安装程序走就行了。
语法糖
方法返回值赋值
func TestOk(t *testing.T) {
a, err := A()
fmt.Println(a)
fmt.Println(err.Error())
}
// A 这里先定义返回变量值的名字,后面可以通过return来进行直接返回
func A() (a int, err error) {
a = 1
err = errors.New("错误")
return
}
go基础部分
变量赋值
func main() {
var a = "Hello" //可以被修改,匿名类型,用于定义默认的值
const b = "World" //无法被修改
a = "Ok"
fmt.Println(a + b)
//申明类型,用于接受确定的类型,定义全局变量使用
var sum int //定义变量
fmt.Println(sum)
var list []string //定义数组
fmt.Println(list)
var hashMap map[string]string //定义map
fmt.Println(hashMap)
}
流程语句
- 语法控制
func main() {
var list = []string{"Hello", "World"}
for i := 0; i < 3; i++ { //普通for循环
fmt.Printf("打印:%v\n", i)
}
for i, item := range list { //for增强
fmt.Printf("下标:%v,属性:%v\n", i, item)
}
if true {
fmt.Println("真")
}
var count = 3
for count > 0 { //死循环 => for true {}
fmt.Println("死循环")
time.Sleep(1 * time.Second)
count--
}
}
Map和List
func main() {
//map
hashMap := make(map[string]string, 0)
hashMap["A"] = "HelloWorld" //插入
fmt.Println(hashMap["A"]) //获取
delete(hashMap, "A") //删除
fmt.Println(hashMap)
//list
list := make([]string, 0)
list = append(list, "Hello", "World")
fmt.Println(list[0]) //获取
fmt.Println(list[1:]) //截取
list = append(list[:1], list[2:]...) //删除
fmt.Println(list)
var i = 1
list = append(list[0:i], list[i-1:]...) //插入元素
list[0] = "Ok"
fmt.Println(list)
}
异常处理
func Test1(t *testing.T) {
defer func() {
if r := recover();r!=nil{
log.Printf("%v",r)
}
}()
panic("异常示例1")
}
自定义错误类型
type ServiceError struct {
msg string
}
func IsServiceError(a any) bool {
switch a.(type) {
case *ServiceError:
return true
case ServiceError:
return true
}
return false
}
func NewServiceError(msg string) *ServiceError {
return &ServiceError{msg: msg}
}
func (s ServiceError) Error() string {
return s.msg
}
func (s ServiceError) RuntimeError() {
panic(s.msg)
}
- 测试
func main() {
defer func() {
if r := recover(); r != nil {
log.Println(config.IsServiceError(r)) //false
log.Println(r)
}
}()
//panic(config.NewServiceError("自定义错误!")) //这个使用,并注释下面一行,则为true
panic("自定义错误!")
}
闭包
func Print() func(a int) int { //闭包函数,返回值必须一致
i := 1
return func(a int) int {
fmt.Println(i) //内部使用外部!
return a
}
}
接口与结构体
// UserService 接口在go变量想要被外部访问,则需要首字母大写
type UserService interface {
Add(str string)string
Print()
}
// UserServiceImpl 结构体
type UserServiceImpl struct {
Title string
Name string
}
func (UserServiceImpl) Add(str string)string {
return str
}
func (UserServiceImpl) Print() {
fmt.Println("HelloWorld")
}
// var book = UserServiceImpl{"a","b"} //创建对象
指针概念
- 带&号则代表传递指针,在其方法里面执行的修改可以影响其原变量。否则则不影响!
// 查看列表 ok
func userList(c *gin.Context) {
var where entity.User
err := c.Bind(&where)
if err != nil {
fmt.Println(err)
}
fmt.Println(where)
var users []entity.User
config.Db.Where(&where).Find(&users)
c.JSON(http.StatusOK, util.OkData(users))
}
多线程通道
- 模拟多线程执行任务进行结果返回!
func main() {
a := make(chan int)
b := make(chan int)
go func() {
time.Sleep(3 * time.Second)
a <- 1011
}()
go func() {
time.Sleep(2 * time.Second)
b <- 1111
}()
// 使用 <-b , <-a 阻塞来获取返回数据,多线程处理任务时使用
log.Println(<-b)
log.Println(<-a)
}
Go实践
- 方法执行必须返回副本,而不能返回指针。否则list类型无法遍历。
开源库
- 库都很简洁明了
- 第三方开源库
- https://gorm.io/zh_CN/
- https://gin-gonic.com/zh-cn/
- https://github.com/golang-jwt/jwt
- https://github.com/go-redis/redis
- https://github.com/go-yaml/yaml
- https://github.com/mongodb/mongo-go-driver
- https://gitee.com/licheng1013/go-util.git
- https://github.com/go-gomail/gomail
- https://github.com/gorilla/websocket
高级部分
- 以下都是基础阶段用不到的内容
镜像配置
- 用于下载第三方库的国内代理
- https://goproxy.cn/
微服务
- 微服务开发框架
- https://go-zero.dev/cn/
多模块开发
- 在根目录下初始化 go work 会创建一个 go.work 文件
- go work init
- 创建 user 目录并进入,执行以下命令创建 go 模块
- go mod init user
- 在根目录的work文件引入
use (
core
user
)
context上下文
- 上下文
var contextData = context.Background()
const Key = "Key"
// SetContext 设置上下文数据,这里传入的类型要与取出来的类型一致
func SetContext(v int64) {
contextData = context.WithValue(contextData, Key, v)
}
// GetContext 获取上下文数据
func GetContext() int64 {
value := contextData.Value(Key)
if value == nil {
panic("没有数据")
}
return value.(int64)
}
互斥锁
// 互斥锁 , 每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
var lock sync.Mutex
//var lock sync.RWMutex
var v = 0
func main() {
for i := 0; i < 10; i++ {
go sum()
}
//fmt.Println(<-str)
time.Sleep(5 * time.Second)
fmt.Println(v)
}
func sum() {
for i := 0; i < 10000; i++ {
lock.Lock()
v++
lock.Unlock()
}
}
单元测试
- sort_test.go
- 以_test结尾的go文件就是测试
- 测试分为三个步骤
- 1: 输入测试数据
- 2: 执行测试的功能
- 3: 验证测试的功能
工具类
Jwt
- go get -u github.com/golang-jwt/jwt/v4
package util
import (
"fmt"
"github.com/golang-jwt/jwt/v4"
"time"
)
const key = "izVguZPRsBQ5Rqw6dhMvcIwy8_9lQnrO3vpxGwPxfAxDs"
const UserIdKey = "userId"
const expireTimeKey = "expireTime"
func GetToken(id interface{}) string {
mySigningKey := []byte(key)
claims := &jwt.MapClaims{
UserIdKey: id,
expireTimeKey: time.Now(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
t, err := token.SignedString(mySigningKey)
if err != nil {
panic(err)
}
return t
}
// GetUserId 获取token解析,请使用 GetTokenParse 替代
// Deprecated
func GetUserId(t string) string {
return GetTokenParse(t)
}
// GetTokenParse 获取token解析
func GetTokenParse(t string) string {
token, err := jwt.Parse(t, func(token *jwt.Token) (interface{}, error) {
return []byte(key), nil
})
//log.Println(token.Header)
//log.Println(token.Claims)
if err != nil {
panic(err)
}
id := (token.Claims.(jwt.MapClaims))["userId"]
return fmt.Sprintf("%v", id)
}
打包
set GOOS=linux
set GOARCH=amd64
go build -ldflags "-w -s" -o ./main main.go