how to use golang

go环境设置

go get 代理设置

  • 对应的shell代理设置,cmd/powershell
  • git代理设置
set http_proxy=http://127.0.0.1:1081
set https_proxy=http://127.0.0.1:1081
$ENV:http_proxy="http://127.0.0.1:1081"
$ENV:https_proxy="http://127.0.0.1:1081"
git config --global http.proxy http://127.0.0.1:1081
git config --global https.proxy http://127.0.0.1:1081
git config --global --unset http.proxy
git config --global --unset https.proxy

go mod

go mod download  //下载依赖包
go mod edit  //工具或脚本编辑go.mod
go mod graph  //打印模块依赖图
go mod init  //在当前目录初始化mod
go mod tidy  //拉取缺少的模块,移除不用的模块。
go mod vendor  //将依赖复制到vendor下
go mod verify  //验证依赖是否正确
go mod why  //解释为什么需要依赖
go list -m -json all  //依赖详情

go mod 练习

首先
mkdir go_t && cd go_t
go mod init app
go get -u github.com/codesenberg/bombardier // 这是一个http压测客户端,
cat go.sum // go.sum 安装了没有用的东西,因为打算全局安装,但是并不想要引入当前项目
go mod tidy // 无效 因为当前目录没有impact 任何go的包
// 创建一个go文件
go mod tidy  
cat go.sum
// 不会影响全局
go install  github.com/codesenberg/bombardier@latest 

go env

go 1.13提供了 go env -w命令来写环境变量

go env -w XXX="XXX"
go env -u XXX

go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

win: 用户\AppData\Roaming\go\env
linux: /root/.config/go/env

关于下载库和下载软件

以下基于 go 1.17

如果你要下载一个由go编写的的可执行程序,你应该执行 go install xxxx。这会在 GO_PATH/bin/ 下安装可执行文件。
如果你要引用第三方库进行代码开发,你可以使用 go get -d (仅下载代码不进行编译)。

可以认为目前是 go 1.17 还是一个过渡时期,未来 go get应该不再进行编译操作,-d 会演变为默认参数。而 go install则进化为下载可执行软件的专用方法。

目前 go 1.17 用 go get 还是可以下载+编译的。未来应该是不能这么操作了

基础

包推荐

练习

闭包练习

package main 
func add(x1, x2 int) func(x3 int, x4 int) (int, int, int) {
	i := 0
	return func(x3 int, x4 int) (int, int, int) {
		i++
		return i, x1 + x2, x3 + x4
	}
}

gin

gorm

gorm 分表写法

假设 user 按照 uid 分表。
关键点:设置db.Table,同时在查询前调用Scopes,因为Scopes传递的是闭包,所以可以编写一个构建闭包的函数进行设置。


type KUser struct {
	ID              uint32    `gorm:"primaryKey;column:id;type:int(10) unsigned;not null"`              // 用户表自增id
	UId             uint64    `gorm:"unique;column:uid;type:bigint(20) unsigned;not null"`              // 用户中心passId
	NickName        string    `gorm:"column:nick_name;type:varchar(255);not null;default:''"`           // 用户昵称
}

func (u KUser) getSuffixByUid() uint64 {
	return u.UId % uint64(32)
}

type kUserRepository struct {
}

var kur *kUserRepository

func init() {
	kur = new(kUserRepository)
}

func setGetSuffix(suffix int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		return db.Table("user_" + types.ToString(suffix))
	}
}

func setGetSuffixByUid(uid int64) func(db *gorm.DB) *gorm.DB {
	return setGetSuffix(getSuffixByUid(uid))
}

func getSuffixByUid(uid int64) int {
	return types.ToInt(uid % 32)
}

func (kur kUserRepository) FindBySuffix(suffix int) []KUser {
	var kUsers []KUser
	r := dbPool.GetDB().Scopes(setGetSuffix(suffix)).Find(&kUsers)
	fmt.Println(r.Error)
	return kUsers
}

func GetKUserRepository() *kUserRepository {
	return kur
}

model 开发

go 模块的开发并不复杂,但是其为了兼容老版本,所采取的策略比较有意思。相比与 composernpm 这种每个包指定版本的做法。go mod 可以在一个项目下依赖同一个库的不同版本的代码。

首先

mkdir hello-go-mod
cd hello-go-mod
git init 
go mod init github.com/eatmeatball/hello-go-mod
mkdir hello
cd hello
echo "package hello


func Hello() string{
	return "hello"
}" > function.go

cd ..
git add .
git commit -m 'code a lib for go'
git push

当推送完成之后你就可以使用

go get -u  github.com/eatmeatball/hello-go-mod

在其他项目拉取该项目了。默认为v0.0.0

接下来就是不一样的地方了。你可以在这个项目上打tag,当tagv1.x.x/v0.x.x 拉取是没有任何问题的。

当你把 tag 打到 v2.x.x。你会发现无法拉取

拉取代码的时候会出现

go get: github.com/eatmeatball/hello@v2.0.1: reading https://goproxy.cn/github.com/eatmeatball/hello/@v/v2.0.1.info: 404 Not Found
        server response: not found: github.com/eatmeatball/hello@v2.0.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2

是不是满脑子充满了问号?

这里有一篇官方的blogv2-go-modules。官网的内容中定义了一个原则

如果旧包和新包的导入路径相同,新包必须向后兼容旧的包
对比以下之前用过的包管理,是不是有点不一样?比如 php 的 composer ,里面的高版本都是为了进行破坏性的升级才修改的。升级高版本是不是要修改代码?虽然go中高版本也可以写api破坏性的代码,但是其高于v2的版本通过go get 后本地位置是不一样的。所以在go的项目中,你可以在一个项目中同时引入一个库的v1,v2,v3代码进行编译。这里如果你想要发布非v0v1的版本你需要把go.mod文件修改

修改前

module github.com/eatmeatball/hello-go-mod

go 1.16

修改后

module github.com/eatmeatball/hello-go-mod/v3

go 1.16

这样,即使你发布的新版本存在破坏性,但是拉取的时候go按照顶级版本划分了目录,就可以使其同时使用高低版本代码

https://github.com/rsc/quote/tree/master

根据官网的demo你可以一个项目多个目录,也可以一个项目多个分支来控制版本。

cgo

GCC原名为GNU C语言编译器(GNU C Compiler),只能处理C语言。但其很快扩展,变得可处理C++,后来又扩展为能够支持更多编程语言,如Fortran、Pascal、Objective -C、Java、Ada、Go以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件

MinGW-w64下载地址:https://sourceforge.net/projects/mingw-w64/files/

选择合适的版本

  • i686纯32位版供32位win系统使用
  • x86_64是64位系统用的版本
  • seh结尾是纯64位编译
  • sjlj结尾是32 64两种编译,需加-m32或-m64参数
  • posix通常用于跨平台,比win32兼容性好一些

最终下载版本x86_64-posix-sjlj

解压后bin目录加入到环境变量

取苹果

package main

import (
	"fmt"
	"time"
)

func  main() {

	fmt.Println("this is a demoC")

	plate := make(chan int)
	apple := make(chan int)
	orange := make(chan int)
	go func() {
		for {
			time.Sleep(time.Second)
			dadPlate := <-plate
			fmt.Println("盘子可以放入一个水果 dad Plate", dadPlate)
			apple <- 1
			fmt.Println("dad放入一个苹果")
		}
	}()

	go func() {
		for {
			time.Sleep(time.Second)
			momPlate := <-plate
			fmt.Println("盘子可以放入一个水果mom Plate", momPlate)
			orange <- 1
			fmt.Println("mom放入一个橘子")
		}

	}()

	go func() {
		for {
			time.Sleep(time.Second)
			sonOrange := <-orange
			fmt.Println("儿子取走一个橘子 sonOrange Plate", sonOrange)
			plate <- 1
			fmt.Println("儿子清空盘子")
		}

	}()
	go func() {
		for {
			time.Sleep(time.Second)
			daughterApple := <-apple
			fmt.Println("女儿取走一个苹果 daughterApple Plate", daughterApple)
			plate <- 1
			fmt.Println("女儿清空盘子")
		}
	}()
	plate <- 1
	for {
		time.Sleep(time.Second)
	}
}

评论列表