github.com/lestrrat-go/libxml2 这个xpath包在windows下无法使用

马化云 发表了文章 • 0 个评论 • 1260 次浏览 • 2023-08-18 12:11 • 来自相关话题

报错信息:
 
(base) PS C:\git\qiniu_web_gin> go run .\main.go
# github.com/lestrrat-go/libxml2/xpath
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:40:35: undefined: clib.XMLXPathObjectType
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:45:14: undefined: clib.XMLXPathObjectFloat64
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:50:14: undefined: clib.XMLXPathObjectBool
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:74:18: undefined: clib.XMLXPathObjectNodeList
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:91:18: undefined: clib.XMLXPathObjectNodeList
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:124:7: undefined: clib.XMLXPathFreeObject
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:129:19: undefined: clib.XMLXPathCompile
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:149:7: undefined: clib.XMLXPathFreeCompExpr
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:163:22: undefined: clib.XMLXPathNewContext
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:179:14: undefined: clib.XMLXPathContextSetContextNode
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:179:14: too many errors
(base) PS C:\git\qiniu_web_gin> go get github.com/lestrrat-go/libxml2
(base) PS C:\git\qiniu_web_gin>

然后到作者的官网上逛了一圈,出现这个问题,需要自己编译一个libxml2 windows版本的
 
官方给出的是源码:
libxml2-2.11.5-win-build Latest
Corresponding to official release version 2.11.5.





 





 
然后编译C的源码,需要很多的工具链和依赖。
windows至少需要Visual Studio, 不是vs code呢。 Visual Studio安装完,至少要被占用10GB的空间。
 





 
libxml2 + iconv + msvc 在windows下生成使用库
为了跨平台的解析xml,偶然获得Linux下比较好用的一个xml的解析库libxml2,使用起来确实比较简单,方便;但移植到windows下后发下使用上存在问题:
无法解析格式位GB2312类型的XML文件,但由于一些外部因素,Windows下必须使用GB2312格式
在网上查看了诸多教程,有很多编译生成libxml2库的文章,但都不支持iconv,仔细阅读README后,终于生成了可用的libxml2.lib库,记录下来备用

操作系统:windows 7 x64
版本:libiconv-1.15, libxml2 Github版本
Visual Studio版本:vs2015
Cygwin:x64

以下操作皆为生成x64位库,32位的基本类似,可以查看具体的README。
 
所以想想还是算了,直接切换到ubuntu开发了。惹不起,还躲不起吗 :(
 
我:@lestrrat Hi, is that mean it can't work on windows if i dont build it with visual studio or cgywin like?

作者:It's the same as when you are building a C program. You build in the same arch/os as the where you intend to run the program.

我:Thanks a lot. Instsall vs environment taks lots of time, so i switch to the ubuntu to "quick fix this issue" :(
逃-》
 
  查看全部
报错信息:
 
(base) PS C:\git\qiniu_web_gin> go run .\main.go
# github.com/lestrrat-go/libxml2/xpath
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:40:35: undefined: clib.XMLXPathObjectType
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:45:14: undefined: clib.XMLXPathObjectFloat64
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:50:14: undefined: clib.XMLXPathObjectBool
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:74:18: undefined: clib.XMLXPathObjectNodeList
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:91:18: undefined: clib.XMLXPathObjectNodeList
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:124:7: undefined: clib.XMLXPathFreeObject
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:129:19: undefined: clib.XMLXPathCompile
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:149:7: undefined: clib.XMLXPathFreeCompExpr
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:163:22: undefined: clib.XMLXPathNewContext
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:179:14: undefined: clib.XMLXPathContextSetContextNode
C:\Users\xda\go\pkg\mod\github.com\lestrrat-go\libxml2@v0.0.0-20201123224832-e6d9de61b80d\xpath\xpath.go:179:14: too many errors
(base) PS C:\git\qiniu_web_gin> go get github.com/lestrrat-go/libxml2
(base) PS C:\git\qiniu_web_gin>

然后到作者的官网上逛了一圈,出现这个问题,需要自己编译一个libxml2 windows版本的
 
官方给出的是源码:
libxml2-2.11.5-win-build Latest
Corresponding to official release version 2.11.5.


3476aaa157ac45f4a3ae4da04274b536.png

 

8599f7480474440b8273abb5a58aa41f.png

 
然后编译C的源码,需要很多的工具链和依赖。
windows至少需要Visual Studio, 不是vs code呢。 Visual Studio安装完,至少要被占用10GB的空间。
 

213ce11b6a0443e8b49b9787d6ac1320.png

 
libxml2 + iconv + msvc 在windows下生成使用库
为了跨平台的解析xml,偶然获得Linux下比较好用的一个xml的解析库libxml2,使用起来确实比较简单,方便;但移植到windows下后发下使用上存在问题:
无法解析格式位GB2312类型的XML文件,但由于一些外部因素,Windows下必须使用GB2312格式
在网上查看了诸多教程,有很多编译生成libxml2库的文章,但都不支持iconv,仔细阅读README后,终于生成了可用的libxml2.lib库,记录下来备用

操作系统:windows 7 x64
版本:libiconv-1.15, libxml2 Github版本
Visual Studio版本:vs2015
Cygwin:x64

以下操作皆为生成x64位库,32位的基本类似,可以查看具体的README。

 
所以想想还是算了,直接切换到ubuntu开发了。惹不起,还躲不起吗 :(
 
我:@lestrrat Hi, is that mean it can't work on windows if i dont build it with visual studio or cgywin like?

作者:It's the same as when you are building a C program. You build in the same arch/os as the where you intend to run the program.

我:Thanks a lot. Instsall vs environment taks lots of time, so i switch to the ubuntu to "quick fix this issue" :(

逃-》
 
 

golang执行系统shell命令,并获取返回内容

马化云 发表了文章 • 0 个评论 • 1822 次浏览 • 2023-03-26 11:42 • 来自相关话题

可以使用 os/exec 包中的 Command 函数执行 shell 命令,并使用 CombinedOutput 方法获取命令的输出结果和退出码。示例代码如下:import (
"fmt"
"os/exec"
)

func runCommand(command string) (string, error) {
cmd := exec.Command("sh", "-c", command)
output, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
return string(output), nil
}

调用 runCommand 函数即可执行 shell 命令,并获取命令的输出结果。如果命令执行成功,则返回输出结果和 nil,否则返回空字符串和错误信息。需要注意的是,由于 CombinedOutput 方法会等待命令执行完毕才返回,因此在执行耗时较长的命令时可能会阻塞程序的执行。可以使用 Start 和 Wait 方法实现异步执行命令的效果。 查看全部
可以使用 os/exec 包中的 Command 函数执行 shell 命令,并使用 CombinedOutput 方法获取命令的输出结果和退出码。示例代码如下:
import (
"fmt"
"os/exec"
)

func runCommand(command string) (string, error) {
cmd := exec.Command("sh", "-c", command)
output, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
return string(output), nil
}


调用 runCommand 函数即可执行 shell 命令,并获取命令的输出结果。如果命令执行成功,则返回输出结果和 nil,否则返回空字符串和错误信息。需要注意的是,由于 CombinedOutput 方法会等待命令执行完毕才返回,因此在执行耗时较长的命令时可能会阻塞程序的执行。可以使用 Start 和 Wait 方法实现异步执行命令的效果。

golang mysql count(*) 的写法

马化云 发表了文章 • 0 个评论 • 1744 次浏览 • 2022-12-15 22:17 • 来自相关话题

mysql最为常用的语句。
 
使用golang标准库 database/sql 实现:
 
 
package main

import (
"database/sql"
"fmt"
"log"

_ "github.com/lib/pq"
)

func main() {
var count int

db, err := sql.Open("postgres", "user=test password=test dbname=foo sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()

row := db.QueryRow("SELECT COUNT(*) FROM table_name")
err := row.Scan(&count)
if err != nil {
log.Fatal(err)
}

fmt.Println(count)

即可。
 
  查看全部
mysql最为常用的语句。
 
使用golang标准库 database/sql 实现:
 
 
package main

import (
"database/sql"
"fmt"
"log"

_ "github.com/lib/pq"
)

func main() {
var count int

db, err := sql.Open("postgres", "user=test password=test dbname=foo sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()

row := db.QueryRow("SELECT COUNT(*) FROM table_name")
err := row.Scan(&count)
if err != nil {
log.Fatal(err)
}

fmt.Println(count)
}
 
即可。
 
 

golang mysql包 database/sql的基本操作:增删改查 (go sql操作 保存这篇文章就足够了)

马化云 发表了文章 • 0 个评论 • 1840 次浏览 • 2022-12-15 12:06 • 来自相关话题

如果不是使用gorm,直接操作底层mysql命令,那么最常使用的是 database/sql 这个包了。

下面的是一些常见的操作,如果需要写底层sql语句,使用频率极高,值得收藏。
 /*
* @Author: 30daydo
* @FilePath: /go110/go-012/g012.go
* @Description: Go 数据库基本操作
*/

package main

import (
"database/sql"
"fmt"
"runtime"

_ "github.com/go-sql-driver/mysql"
)

/**
// 创建 user 表
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户信息表'
**/

// 全局对象 db
var db *sql.DB

// 定义一个 user 结构体接收数据:
type user struct {
id int
age int
name string
}

// 始化数据库的函数
func initDB() (err error) {

// 构建连接的 dsn 格式是:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
dsn := "user:password@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"

// 给全局变量赋值, 注意这里不要使用 :=
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Println("初始化数据库失败")
return err
}

// 校验dsn是否正确
fmt.Println("尝试与数据库建立连接...")
err = db.Ping()
if err != nil {
fmt.Println("连接失败")
return err
}
fmt.Println("连接成功")

db.SetMaxOpenConns(2000) // 设置最大打开连接数
db.SetMaxIdleConns(10) // 设置最大空闲连接数

return nil
}

// 插入数据
func insertRow(name string, age int) int64 {

sqlStr := "INSERT INTO user(name, age) VALUES (?,?)"

ret, err := db.Exec(sqlStr, name, age)

if err != nil {
fmt.Printf("插入失败, err: %v\n", err)
return 0
}

// 新插入数据的 id
insertId, err := ret.LastInsertId()
if err != nil {
fmt.Printf("获取新插入数据的 ID 失败, err:%v\n", err)
return 0
}
fmt.Printf("插入成功, ID 为 %d.\n", insertId)

return insertId
}

// 查询单条数据记录
func queryRow(rowId int64) {
sqlStr := "SELECT id, name, age FROM user WHERE id = ?"
var u user
// 确保 QueryRow 之后调用 Scan 方法,释放持有的数据库链接
err := db.QueryRow(sqlStr, rowId).Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("未找到记录, 查询失败, err: %v\n", err)
return
}
fmt.Printf("查询数据成功, id: %d name: %s age: %d \n", u.id, u.name, u.age)
}

// 更新数据
func updateRow(rowId int64, newAge int) {
sqlStr := "UPDATE user SET age=? WHERE id = ?"
ret, err := db.Exec(sqlStr, newAge, rowId)
if err != nil {
fmt.Printf("更新失败 , err:%v\n", err)
return
}
// 操作影响的行数
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("更新成功, 影响行数为: %d\n", n)
}

// 删除数据
func deleteRow(rowId int64) {
sqlStr := "DELETE FROM user WHERE id = ?"
ret, err := db.Exec(sqlStr, rowId)
if err != nil {
fmt.Printf("删除失败, err: %v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("删除成功, 影响行数为: %d\n", n)
}

// 查询多行
func queryMultiRow() {
sqlStr := "SELECT id, name, age FROM user WHERE id > ?"
rows, err := db.Query(sqlStr, 0)
if err != nil {
fmt.Printf("查询失败, err:%v\n", err)
return
}
// 重要:关闭 rows, 释放持有的数据库链接
defer rows.Close()

// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("查询多行数据失败, err:%v\n", err)
return
}
fmt.Printf("当前数据 id: %d name: %s age: %d\n", u.id, u.name, u.age)
}
}

func main() {
// 使用内置函数打印
println("Hello", "菜鸟实战")

// 初始化数据库
initDB()

// 插入数据
var id1 = insertRow("唐遇春", 17)
var id2 = insertRow("冯显", 38)
var id3 = insertRow("花千里", 20)

// 查询多行数据
queryMultiRow()

// 更新数据
updateRow(id2, 35)

// 查询单行数据
queryRow(id2)

// 删除数据
deleteRow(id1)

// 查询多行数据
queryMultiRow()
queryRow(id3)

// 当前版本
fmt.Printf("版本: %s \n", runtime.Version())
}
 
当然,上面的语句也可以不用Prepare的写法,直接插入进去:
 
func insertDirect() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "INSERT INTO user(id, name, pwd) VALUES(?, ?, ?)"
res, err := db.Exec(sql, 13, "Jobs", "444555")
checkErr(err)
fmt.Println(res.LastInsertId())

} 查看全部
如果不是使用gorm,直接操作底层mysql命令,那么最常使用的是 database/sql 这个包了。

下面的是一些常见的操作,如果需要写底层sql语句,使用频率极高,值得收藏。
 
/*
* @Author: 30daydo
* @FilePath: /go110/go-012/g012.go
* @Description: Go 数据库基本操作
*/

package main

import (
"database/sql"
"fmt"
"runtime"

_ "github.com/go-sql-driver/mysql"
)

/**
// 创建 user 表
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户信息表'
**/

// 全局对象 db
var db *sql.DB

// 定义一个 user 结构体接收数据:
type user struct {
id int
age int
name string
}

// 始化数据库的函数
func initDB() (err error) {

// 构建连接的 dsn 格式是:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
dsn := "user:password@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"

// 给全局变量赋值, 注意这里不要使用 :=
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Println("初始化数据库失败")
return err
}

// 校验dsn是否正确
fmt.Println("尝试与数据库建立连接...")
err = db.Ping()
if err != nil {
fmt.Println("连接失败")
return err
}
fmt.Println("连接成功")

db.SetMaxOpenConns(2000) // 设置最大打开连接数
db.SetMaxIdleConns(10) // 设置最大空闲连接数

return nil
}

// 插入数据
func insertRow(name string, age int) int64 {

sqlStr := "INSERT INTO user(name, age) VALUES (?,?)"

ret, err := db.Exec(sqlStr, name, age)

if err != nil {
fmt.Printf("插入失败, err: %v\n", err)
return 0
}

// 新插入数据的 id
insertId, err := ret.LastInsertId()
if err != nil {
fmt.Printf("获取新插入数据的 ID 失败, err:%v\n", err)
return 0
}
fmt.Printf("插入成功, ID 为 %d.\n", insertId)

return insertId
}

// 查询单条数据记录
func queryRow(rowId int64) {
sqlStr := "SELECT id, name, age FROM user WHERE id = ?"
var u user
// 确保 QueryRow 之后调用 Scan 方法,释放持有的数据库链接
err := db.QueryRow(sqlStr, rowId).Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("未找到记录, 查询失败, err: %v\n", err)
return
}
fmt.Printf("查询数据成功, id: %d name: %s age: %d \n", u.id, u.name, u.age)
}

// 更新数据
func updateRow(rowId int64, newAge int) {
sqlStr := "UPDATE user SET age=? WHERE id = ?"
ret, err := db.Exec(sqlStr, newAge, rowId)
if err != nil {
fmt.Printf("更新失败 , err:%v\n", err)
return
}
// 操作影响的行数
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("更新成功, 影响行数为: %d\n", n)
}

// 删除数据
func deleteRow(rowId int64) {
sqlStr := "DELETE FROM user WHERE id = ?"
ret, err := db.Exec(sqlStr, rowId)
if err != nil {
fmt.Printf("删除失败, err: %v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("获取影响函数失败, err: %v\n", err)
return
}
fmt.Printf("删除成功, 影响行数为: %d\n", n)
}

// 查询多行
func queryMultiRow() {
sqlStr := "SELECT id, name, age FROM user WHERE id > ?"
rows, err := db.Query(sqlStr, 0)
if err != nil {
fmt.Printf("查询失败, err:%v\n", err)
return
}
// 重要:关闭 rows, 释放持有的数据库链接
defer rows.Close()

// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("查询多行数据失败, err:%v\n", err)
return
}
fmt.Printf("当前数据 id: %d name: %s age: %d\n", u.id, u.name, u.age)
}
}

func main() {
// 使用内置函数打印
println("Hello", "菜鸟实战")

// 初始化数据库
initDB()

// 插入数据
var id1 = insertRow("唐遇春", 17)
var id2 = insertRow("冯显", 38)
var id3 = insertRow("花千里", 20)

// 查询多行数据
queryMultiRow()

// 更新数据
updateRow(id2, 35)

// 查询单行数据
queryRow(id2)

// 删除数据
deleteRow(id1)

// 查询多行数据
queryMultiRow()
queryRow(id3)

// 当前版本
fmt.Printf("版本: %s \n", runtime.Version())
}

 
当然,上面的语句也可以不用Prepare的写法,直接插入进去:
 
func insertDirect() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "INSERT INTO user(id, name, pwd) VALUES(?, ?, ?)"
res, err := db.Exec(sql, 13, "Jobs", "444555")
checkErr(err)
fmt.Println(res.LastInsertId())

}

golang 插入redis 集合,并判断元素是否存在

李魔佛 发表了文章 • 0 个评论 • 1917 次浏览 • 2022-06-20 17:26 • 来自相关话题

代码如下:
1. "server/service" 是当前的报名
2. 用的go-redis这个库
 
判断元素是否在集合中:

conn.SIsMember("User", sign).Result()

完整代码:
package cache

import (
"server/service"
"fmt"
"github.com/go-redis/redis"
)

type Cache struct {
conn *redis.Client
}

func (this *Cache) CacheInit() {
this.connect()

}
func (this *Cache) connect() {
conf := service.ReadRedisConfig()
this.conn = redis.NewClient(&redis.Options{
Addr: conf.Addr,
Password: conf.Password,
DB: conf.DB,
})

}
func (this *Cache) Get(id string) (string, bool) {
result, err := this.conn.Get(id).Result()
if err != nil {
fmt.Println(err)
return "", false
}
return result, true
}

func (this *Cache) Set(id string, content string) bool {
_, err := this.conn.Set(id, content, 0).Result()
if err != nil {
fmt.Println(err)
return false
} else {
return true
}
}

func (this *Cache) CheckUserExist(sign string) bool {
result, err := this.conn.SIsMember("User", sign).Result()
if err != nil {
fmt.Println(err)
return false
}
return result
}

func (this *Cache) AddUser(name string) bool {
_, err := this.conn.SAdd("User", name).Result()
if err != nil {
fmt.Println(err)
return false
} else {
return true
}

}

github地址:
https://github.com/Rockyzsu/BondInfoServer.git
  查看全部
代码如下:
1. "server/service" 是当前的报名
2. 用的go-redis这个库
 
判断元素是否在集合中:

conn.SIsMember("User", sign).Result()

完整代码:
package cache

import (
"server/service"
"fmt"
"github.com/go-redis/redis"
)

type Cache struct {
conn *redis.Client
}

func (this *Cache) CacheInit() {
this.connect()

}
func (this *Cache) connect() {
conf := service.ReadRedisConfig()
this.conn = redis.NewClient(&redis.Options{
Addr: conf.Addr,
Password: conf.Password,
DB: conf.DB,
})

}
func (this *Cache) Get(id string) (string, bool) {
result, err := this.conn.Get(id).Result()
if err != nil {
fmt.Println(err)
return "", false
}
return result, true
}

func (this *Cache) Set(id string, content string) bool {
_, err := this.conn.Set(id, content, 0).Result()
if err != nil {
fmt.Println(err)
return false
} else {
return true
}
}

func (this *Cache) CheckUserExist(sign string) bool {
result, err := this.conn.SIsMember("User", sign).Result()
if err != nil {
fmt.Println(err)
return false
}
return result
}

func (this *Cache) AddUser(name string) bool {
_, err := this.conn.SAdd("User", name).Result()
if err != nil {
fmt.Println(err)
return false
} else {
return true
}

}

github地址:
https://github.com/Rockyzsu/BondInfoServer.git
 

在中国网络环境下获取Golang.org上的Golang Packages

李魔佛 发表了文章 • 0 个评论 • 1848 次浏览 • 2022-06-16 10:26 • 来自相关话题

在中国网络环境下获取Golang.org上的Golang Packages

背景
目前在中国网络环境下无法访问Golang.org。
问题
不能运行go get golang.org/x/XX来获取Golang packages。

解决方案
方案 A: 使用github 上的镜像

获取Golang Package在github镜像上的路径: golang.org/x/PATH_TO_PACKAGE --> github.com/golang/PATH_TO_PACKAGE.

// Ex:
golang.org/x/net/context --> github.com/golang/net/context
运行go get来安装github镜像的Golang packages。

// Ex:
go get github.com/golang/net/context
你会碰到如下错误提示:

package github.com/golang/net/context:
code in directory /go/src/github.com/golang/net/context
expects import "golang.org/x/net/context"
忽略错误。 Golang的Package的源代码已经成功下载于:
$GOPATH/src/github.com/golang/PATH_TO_PACKAGE.

复制 $GOPATH/src/github.com/golang/PATH_TO_PACKAGE 到 $GOPATH/src/golang.org/x/PATH_TO_PACKAGE.

// Ex:
mkdir $GOPATH/src/golang.org/x -p
cp $GOPATH/src/github.com/golang/net $GOPATH/src/golang.org/x/ -rf
运行 go build 来编译。

方案 B: 使用第三方网站 - https://gopm.io/download

输入包路径即可下载zip文件。 查看全部
在中国网络环境下获取Golang.org上的Golang Packages

背景
目前在中国网络环境下无法访问Golang.org。
问题
不能运行go get golang.org/x/XX来获取Golang packages。

解决方案
方案 A: 使用github 上的镜像

获取Golang Package在github镜像上的路径: golang.org/x/PATH_TO_PACKAGE --> github.com/golang/PATH_TO_PACKAGE.

// Ex:
golang.org/x/net/context --> github.com/golang/net/context
运行go get来安装github镜像的Golang packages。

// Ex:
go get github.com/golang/net/context
你会碰到如下错误提示:

package github.com/golang/net/context:
code in directory /go/src/github.com/golang/net/context
expects import "golang.org/x/net/context"
忽略错误。 Golang的Package的源代码已经成功下载于:
$GOPATH/src/github.com/golang/PATH_TO_PACKAGE.

复制 $GOPATH/src/github.com/golang/PATH_TO_PACKAGE 到 $GOPATH/src/golang.org/x/PATH_TO_PACKAGE.

// Ex:
mkdir $GOPATH/src/golang.org/x -p
cp $GOPATH/src/github.com/golang/net $GOPATH/src/golang.org/x/ -rf
运行 go build 来编译。

方案 B: 使用第三方网站 - https://gopm.io/download

输入包路径即可下载zip文件。

golang gin ajax post 前端与后端的正确写法

李魔佛 发表了文章 • 0 个评论 • 2701 次浏览 • 2022-06-08 18:42 • 来自相关话题

比较常用的场景,记录一下:
前端是一个页面html页面
<script type="text/javascript">
var submitBTN = document.getElementById("url_update");
submitBTN.onclick = function (event) {
// 注意这里是 onclick 函数
console.log("click");
$.ajax({
url: "/update-site1",
type: "POST",
data: {value:1},
cache: false,
contentType: "application/x-www-form-urlencoded",
success: function (data) {
console.log(data);

if (data.code !== 0) {
alert('更新失败')
} else {
new_str = data.res + " " + data.count
$("#txt_content").val(new_str);
alert('更新资源成功!')
}
},
fail: function (data) {
alert("更新失败!");
}
});

$.ajax({
url: "/update-site1",
type: "POST",
data: {value:2},
cache: false,
contentType: "application/x-www-form-urlencoded",
success: function (data) {
console.log(data);

if (data.code !== 0) {
alert('更新失败')
} else {
new_str = data.res + " " + data.count
$("#txt_content").val(new_str);
alert('更新资源成功!')
}
},
fail: function (data) {
alert("更新失败!");
}
})

}

</script>
效果大体上这样的:





 
有几个按钮,然后每个按钮绑定一个点击事件
 
submitBTN.onclick = function (event) {
.....
同上面代码
 
然后在代码里面执行post操作,使用的是ajax封装的方法:
 
注意,contentType用下面的:
contentType: "application/x-www-form-urlencoded",
还有不要把
processData: false,这个设置为false,否则gin的后端解析不到数据
 
写完前端之后,就去后端
 
路由方法:
绑定上面的url update-site1
router.POST("/update-site1", controllers.BaiduSite1)
 然后就是实现
controllers.BaiduSite1 这个方法:
 
func BaiduSite1(ctx *gin.Context) {
if ctx.Request.Method == "POST" {

value := ctx.PostForm("value")
fmt.Println(value)
int_value, err := strconv.Atoi(value)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"res": "",
"count": 0,
})
return
}
res, count := webmaster.PushProcess(1, int_value)
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"res": res,
"count": count,
})
}
}
 获取ajax里面的字段,
使用:context 中的PostForm方法
value := ctx.PostForm("value")
 剩下的就是一些常规的操作方法

最后需要设置json的返回数据
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"res": res,
"count": count,

 完整代码可以到公众号里面获取:
 


 
  查看全部
比较常用的场景,记录一下:
前端是一个页面html页面
<script type="text/javascript">
var submitBTN = document.getElementById("url_update");
submitBTN.onclick = function (event) {
// 注意这里是 onclick 函数
console.log("click");
$.ajax({
url: "/update-site1",
type: "POST",
data: {value:1},
cache: false,
contentType: "application/x-www-form-urlencoded",
success: function (data) {
console.log(data);

if (data.code !== 0) {
alert('更新失败')
} else {
new_str = data.res + " " + data.count
$("#txt_content").val(new_str);
alert('更新资源成功!')
}
},
fail: function (data) {
alert("更新失败!");
}
});

$.ajax({
url: "/update-site1",
type: "POST",
data: {value:2},
cache: false,
contentType: "application/x-www-form-urlencoded",
success: function (data) {
console.log(data);

if (data.code !== 0) {
alert('更新失败')
} else {
new_str = data.res + " " + data.count
$("#txt_content").val(new_str);
alert('更新资源成功!')
}
},
fail: function (data) {
alert("更新失败!");
}
})

}

</script>

效果大体上这样的:

20220608004.jpg

 
有几个按钮,然后每个按钮绑定一个点击事件
 
submitBTN.onclick = function (event) {
.....
同上面代码
 
然后在代码里面执行post操作,使用的是ajax封装的方法:
 
注意,contentType用下面的:
contentType: "application/x-www-form-urlencoded",

还有不要把
processData: false,
这个设置为false,否则gin的后端解析不到数据
 
写完前端之后,就去后端
 
路由方法:
绑定上面的url update-site1
	router.POST("/update-site1", controllers.BaiduSite1)

 然后就是实现
controllers.BaiduSite1 这个方法:
 
func BaiduSite1(ctx *gin.Context) {
if ctx.Request.Method == "POST" {

value := ctx.PostForm("value")
fmt.Println(value)
int_value, err := strconv.Atoi(value)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"res": "",
"count": 0,
})
return
}
res, count := webmaster.PushProcess(1, int_value)
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"res": res,
"count": count,
})
}
}

 获取ajax里面的字段,
使用:context 中的PostForm方法
value := ctx.PostForm("value")

 剩下的就是一些常规的操作方法

最后需要设置json的返回数据
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"res": res,
"count": count,

 完整代码可以到公众号里面获取:
 


 
 

docker部署golang应用 无法下载第三方包 解决办法

李魔佛 发表了文章 • 0 个评论 • 2166 次浏览 • 2022-03-14 14:43 • 来自相关话题

需要把docker内部的环境改一下其GOPROXY地址就可以了。 
ENV GOPROXY https://goproxy.cn
RUN go mod download
RUN go build main.go
 
需要把docker内部的环境改一下其GOPROXY地址就可以了。 
ENV GOPROXY https://goproxy.cn
RUN go mod download
RUN go build main.go

 

性能测试: flask WSGI vs 异步 ASGI vs tornodo vs Golang Gin

李魔佛 发表了文章 • 0 个评论 • 3971 次浏览 • 2022-01-12 10:58 • 来自相关话题

做一个基本的性能基准测试。测试脚本使用是apach benchmark
测试命令:
ab -kc 1000 -n 4000 http://127.0.0.1:5000/
 

代码最精简:
flask wsgi:from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'

if __name__ == '__main__':
app.run(host='0.0.0.0')
得到的结果:
 

ASGI的代码:async def app(scope, receive, send):
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/html']
]
})

await send({
'type': 'http.response.body',
'body': b'Hello This is server running',
'more_body': False
}) 
运行命令:
uvicorn --host 0.0.0.0 simple_asgi:app
 
得到的结果:

 
 
python的tornado
from tornado import ioloop
from tornado import web
class Homepage(web.RequestHandler):

def get(self):
print('get method')
self.write("This is tornado server")

if __name__ == '__main__':
app = web.Application([
("/",Homepage),

])

app.listen(8888)
ioloop.IOLoop.current().start()
 
 
Goland的gin package main

import "github.com/gin-gonic/gin"

// 测试专用

func main() {
r := gin.Default()
r.GET("/index", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Working"})
})
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Working"})
})
r.Run()
}

 
通过requests per second 每秒的请求数:
flask : 1000
uvicorn: 2000
tornoda:3000
go gin:4000

 
所以综合测试结果,flask的性能最烂,go gin的性能最好。差了4倍。
 
转载请注明出处:
http://www.30daydo.com/article/44336
  查看全部
做一个基本的性能基准测试。测试脚本使用是apach benchmark
测试命令:
ab -kc 1000 -n 4000 http://127.0.0.1:5000/
 

代码最精简:
flask wsgi:
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'

if __name__ == '__main__':
app.run(host='0.0.0.0')

得到的结果:
 

ASGI的代码:
async def app(scope, receive, send):
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/html']
]
})

await send({
'type': 'http.response.body',
'body': b'Hello This is server running',
'more_body': False
})
 
运行命令:
uvicorn --host 0.0.0.0 simple_asgi:app
 
得到的结果:

 
 
python的tornado
from tornado import  ioloop
from tornado import web
class Homepage(web.RequestHandler):

def get(self):
print('get method')
self.write("This is tornado server")

if __name__ == '__main__':
app = web.Application([
("/",Homepage),

])

app.listen(8888)
ioloop.IOLoop.current().start()

 
 
Goland的gin
 package main

import "github.com/gin-gonic/gin"

// 测试专用

func main() {
r := gin.Default()
r.GET("/index", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Working"})
})
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Working"})
})
r.Run()
}


 
通过requests per second 每秒的请求数:
flask : 1000
uvicorn: 2000
tornoda:3000
go gin:4000

 
所以综合测试结果,flask的性能最烂,go gin的性能最好。差了4倍。
 
转载请注明出处:
http://www.30daydo.com/article/44336
 

ubuntu goland破解激活教程

李魔佛 发表了文章 • 0 个评论 • 5817 次浏览 • 2022-01-05 13:08 • 来自相关话题

很大小伙伴是使用ubuntu作为主力开发机的。
ubuntu下的goland可以直接到官网下载。
或者在自带的software center。
 
不过goland只能试用一个月,一个月后只能要激活。
 
所以有一个reset插件,可以每次开启goland的时候把激活日期重置,往后推一个月。
 
只需要打开goland,然后把插件拖进去goland的界面即可。

 

 


 
插件获取方式:
关注公众号:
 
30天尝试新事情

 
 
后台回复:goland激活
即可 查看全部
很大小伙伴是使用ubuntu作为主力开发机的。
ubuntu下的goland可以直接到官网下载。
或者在自带的software center。
 
不过goland只能试用一个月,一个月后只能要激活。
 
所以有一个reset插件,可以每次开启goland的时候把激活日期重置,往后推一个月。
 
只需要打开goland,然后把插件拖进去goland的界面即可。

 

 


 
插件获取方式:
关注公众号:
 
30天尝试新事情

 
 
后台回复:goland激活
即可

ubuntu(centos)下golang下载libxml2 报错信息, go 安装libxml2

李魔佛 发表了文章 • 0 个评论 • 2155 次浏览 • 2021-12-29 23:20 • 来自相关话题

ubuntu下golang下载libxml2 报错信息:$ go get -u github.com/lestrrat-go/libxml2
# pkg-config --cflags -- libxml-2.0 Package libxml-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `libxml-2.0.pc' to the PKG_CONFIG_PATH environment variable
No package 'libxml-2.0' found pkg-config: exit status 1 ​ ​
 
因为系统少了个libxml2 开发包:

使用以下命令即可修复:sudo apt install libxml2-dev 
 
如果是centos的话,安装命令:yum install libxml2
yum install libxml2-devel
注意是 libxml2-devel !
别用那种下载源码编译的方法,能用yum就用yum,否则弄得系统一堆依赖问题。 查看全部
ubuntu下golang下载libxml2 报错信息:
$ go get -u github.com/lestrrat-go/libxml2                     
# pkg-config --cflags -- libxml-2.0 Package libxml-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `libxml-2.0.pc' to the PKG_CONFIG_PATH environment variable
No package 'libxml-2.0' found pkg-config: exit status 1 ​ ​

 
因为系统少了个libxml2 开发包:

使用以下命令即可修复:
sudo apt install libxml2-dev
 
 
如果是centos的话,安装命令:
yum install libxml2
yum install libxml2-devel

注意是 libxml2-devel !
别用那种下载源码编译的方法,能用yum就用yum,否则弄得系统一堆依赖问题。

现在很多公众号都是粗制滥造, 代码也没经过验证 就贴上来害人

李魔佛 发表了文章 • 0 个评论 • 2003 次浏览 • 2021-12-27 11:52 • 来自相关话题

来看看这个公众号 :  Golang来啦
 

 
你说函数签名的Counter写错就算了. 但是返回的也是一个指针呀......
 
正确写法
func NewNotSafeCounter() *NotSafeCounter {
return &NotSafeCounter{0}
}
 
  查看全部
来看看这个公众号 :  Golang来啦
 

 
你说函数签名的Counter写错就算了. 但是返回的也是一个指针呀......
 
正确写法
func NewNotSafeCounter() *NotSafeCounter {
return &NotSafeCounter{0}
}

 
 

golang json Unmarshal 无法修改结构体的值。传入指针

李魔佛 发表了文章 • 0 个评论 • 2406 次浏览 • 2021-12-20 12:59 • 来自相关话题

假如我的json文件的格式如下:
 { "username": "root", "password": "123456", "host": "1.1.1.1.", "port": 3306, "db": "admin" }

然后我的定义的结构体:
 
type T struct {

username string `json:"username"`
password string `json:"password"`
host string `json:"host"`
port int `json:"port"`
db string `json:"db"`

}

然后程序里面解析json的代码:var t T
data, err := ioutil.ReadFile(filename)
fmt.Println("read from file")
//fmt.Println(string(data))
if err != nil {
fmt.Println("in error")
fmt.Println(err)
return err
}
err = json.Unmarshal(data, &t)
if err != nil {
fmt.Println("error ")
fmt.Println(err)
return err
}
fmt.Println("outpout ")
fmt.Printf("%v\n", t)
fmt.Println(t)
发现是无法把t的值修改为json文件里面的值,最后的记过输出,还是一个零值的结果体。

后面知道问题所在了,如果定义的结构体的首字母小写的时候,包外的反射是无法修改结构体的值的,也就是只能只读。

所以只需要把结构体的首字母改为大写,问题就可以解决了。type T struct {
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"host"`
Port int `json:"port"`
Db string `json:"db"`
}
json文件里面不用修改,因为
Unmarshal映射的时候可以适配大小写。
  查看全部
假如我的json文件的格式如下:
 
{ "username": "root", "password": "123456", "host": "1.1.1.1.", "port": 3306, "db": "admin" }

然后我的定义的结构体:
 
type T struct { 

username string `json:"username"`
password string `json:"password"`
host string `json:"host"`
port int `json:"port"`
db string `json:"db"`

}


然后程序里面解析json的代码:
var t T
data, err := ioutil.ReadFile(filename)
fmt.Println("read from file")
//fmt.Println(string(data))
if err != nil {
fmt.Println("in error")
fmt.Println(err)
return err
}
err = json.Unmarshal(data, &t)
if err != nil {
fmt.Println("error ")
fmt.Println(err)
return err
}
fmt.Println("outpout ")
fmt.Printf("%v\n", t)
fmt.Println(t)

发现是无法把t的值修改为json文件里面的值,最后的记过输出,还是一个零值的结果体。

后面知道问题所在了,如果定义的结构体的首字母小写的时候,包外的反射是无法修改结构体的值的,也就是只能只读。

所以只需要把结构体的首字母改为大写,问题就可以解决了。
type T struct {
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"host"`
Port int `json:"port"`
Db string `json:"db"`
}

json文件里面不用修改,因为
Unmarshal映射的时候可以适配大小写。
 

为什么现在还有那么多在线的gonlang 字符串生成json struct的网站? Goland IDE一个快捷方式帮你搞定

李魔佛 发表了文章 • 0 个评论 • 1616 次浏览 • 2021-12-20 01:00 • 来自相关话题

在golanad的ide上,敲入 type xx struct{
}
 
在出现的generate from json的页面,把json的字符串输入进去。
 
IDE即可帮你转换为对应的结构体了。 根本就没有在线IDE什么事情了。
在golanad的ide上,敲入 type xx struct{
}
 
在出现的generate from json的页面,把json的字符串输入进去。
 
IDE即可帮你转换为对应的结构体了。 根本就没有在线IDE什么事情了。

golang根据不同返回解析不同结构的json

李魔佛 发表了文章 • 0 个评论 • 2091 次浏览 • 2021-12-20 00:35 • 来自相关话题

// 数据源
{"type":"a_number", "data":{"somenumber":1234}}
{"type":"b_string", "data":{"somestring":"a string", "anotherstring": "a second string"}}` 
如何解析上面返回的json结构体
 
答:json.RawMessage
 
type Head struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}


var msg Head

json.Unmarshal([]byte(jsonString), &msg)

switch msg.Type {
case "a_number":
var detail A
json.Unmarshal([]byte(msg.Data),&detail)
fmt.Println(detail.SomeNumber)
case "b_string":
var detail B
json.Unmarshal([]byte(msg.Data),&detail)
fmt.Println(detail.SomeString)
default:
fmt.Printf("I don't know about type %s!\n", msg.Type)
}
 
就可以解析上面的不规则的结构体了。
 
  查看全部
// 数据源
{"type":"a_number", "data":{"somenumber":1234}}
{"type":"b_string", "data":{"somestring":"a string", "anotherstring": "a second string"}}`
 
如何解析上面返回的json结构体
 
答:json.RawMessage
 
type Head struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}


var msg Head

json.Unmarshal([]byte(jsonString), &msg)

switch msg.Type {
case "a_number":
var detail A
json.Unmarshal([]byte(msg.Data),&detail)
fmt.Println(detail.SomeNumber)
case "b_string":
var detail B
json.Unmarshal([]byte(msg.Data),&detail)
fmt.Println(detail.SomeString)
default:
fmt.Printf("I don't know about type %s!\n", msg.Type)
}

 
就可以解析上面的不规则的结构体了。
 
 

Go 测试题1

李魔佛 发表了文章 • 0 个评论 • 1795 次浏览 • 2021-12-15 12:32 • 来自相关话题

问一个基础
func main() {
v := [...]int{1: 2, 3: 4}
fmt.Println( len(v))
}

这个为什么长度是 4?
 
 
答案:
v数组分配内存[0,2,0,4],所以长度为4。 查看全部
问一个基础
func main() {
v := [...]int{1: 2, 3: 4}
fmt.Println( len(v))
}

这个为什么长度是 4?
 
 
答案:
v数组分配内存[0,2,0,4],所以长度为4。

30天学会Golang

马化云 发表了文章 • 0 个评论 • 2037 次浏览 • 2021-12-04 12:20 • 来自相关话题

适合有一定的编程基础的同学学习。
附github目录图以及github地址
 
https://github.com/Rockyzsu/GolangLearning
 



 同时欢迎关注公众号: 30天尝试新事情

 
  查看全部
适合有一定的编程基础的同学学习。
附github目录图以及github地址
 
https://github.com/Rockyzsu/GolangLearning
 



 同时欢迎关注公众号: 30天尝试新事情

 
 

golang 的sync.Cond Wait 为什么要先Lock之后才能Wait ?

李魔佛 发表了文章 • 0 个评论 • 2321 次浏览 • 2021-11-24 00:09 • 来自相关话题

正确代码: func clickEvent(con *sync.Cond, fn HandleFun, id int) {
fmt.Println("waiting on broadcast")

fmt.Printf("Lock %d\n", id)
con.L.Lock() //需要现先lock
con.Wait()
fn()
defer con.L.Unlock()
}
如果直接Wait,会报错,死锁
 
然后看了看源码:





 
原来Wait函数里面,会先Unlock一次,再去跑runtime通知。
也就是你不Lock一下,进入到Wait函数就会一直锁住。
 
  查看全部
正确代码:
   func clickEvent(con *sync.Cond, fn HandleFun, id int) {        
fmt.Println("waiting on broadcast")

fmt.Printf("Lock %d\n", id)
con.L.Lock() //需要现先lock
con.Wait()
fn()
defer con.L.Unlock()
}

如果直接Wait,会报错,死锁
 
然后看了看源码:

Screenshot_2021-11-24_00-08-04.png

 
原来Wait函数里面,会先Unlock一次,再去跑runtime通知。
也就是你不Lock一下,进入到Wait函数就会一直锁住。
 
 

cannot install, GOBIN must be an absolute path

李魔佛 发表了文章 • 0 个评论 • 3147 次浏览 • 2021-11-22 22:32 • 来自相关话题

原因是因为你的系统环境变量用的相对路径 %GOPATH%/bin
 
把GOPATH替换为完整的路径,比如C:\User\Admin\go\bin 即可解决问题。
原创文章,转载请注明出处: 
http://30daydo.com/article/44290
  查看全部
原因是因为你的系统环境变量用的相对路径 %GOPATH%/bin
 
把GOPATH替换为完整的路径,比如C:\User\Admin\go\bin 即可解决问题。
原创文章,转载请注明出处: 
http://30daydo.com/article/44290
 

gin can not run reasons: c.engine.AppEngine undefined

李魔佛 发表了文章 • 0 个评论 • 1985 次浏览 • 2021-11-22 22:29 • 来自相关话题

gin运行报错:# github.com/gin-gonic/gin
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\context.go:735:13: c.engine.AppEngine undefined (type *Engine ha
s no field or method AppEngine)
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:154:3: unknown field 'UseRawPath' in struct literal of ty
pe Engine
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:156:3: unknown field 'UnescapePathValues' in struct liter
al of type Engine
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:508:11: engine.UseRawPath undefined (type *Engine has no
field or method UseRawPath)
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:510:20: engine.UnescapePathValues undefined (type *Engine
has no field or method UnescapePathValues)
源码:package main

import (
"net/http"

"github.com/gin-gonic/gin"
)

func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello World!")
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
r.Run(":8000")
}
版本兼容性问题,降级到 gin@1.7.2 即可解决问题。
当前最新的版本为1.7.5 
 
降级方法:

go get github.com/gin-gonic/gin@v1.7.2

 
原创文章,转载请注明出处:
http://30daydo.com/article/44289
  查看全部
gin运行报错:
# github.com/gin-gonic/gin
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\context.go:735:13: c.engine.AppEngine undefined (type *Engine ha
s no field or method AppEngine)
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:154:3: unknown field 'UseRawPath' in struct literal of ty
pe Engine
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:156:3: unknown field 'UnescapePathValues' in struct liter
al of type Engine
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:508:11: engine.UseRawPath undefined (type *Engine has no
field or method UseRawPath)
C:\Users\xda\go\pkg\mod\github.com\gin-gonic\gin@v1.7.5\gin.go:510:20: engine.UnescapePathValues undefined (type *Engine
has no field or method UnescapePathValues)

源码:
package main

import (
"net/http"

"github.com/gin-gonic/gin"
)

func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello World!")
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
r.Run(":8000")
}

版本兼容性问题,降级到 gin@1.7.2 即可解决问题。
当前最新的版本为1.7.5 
 
降级方法:

go get github.com/gin-gonic/gin@v1.7.2

 
原创文章,转载请注明出处:
http://30daydo.com/article/44289
 

golang文件操作之 移动文件

李魔佛 发表了文章 • 0 个评论 • 5067 次浏览 • 2021-11-21 20:35 • 来自相关话题

golang的内库os里面并没有Move的函数,如果要移动文件可以使用os.Rename
 package main

import (
"log"
"os"
)

func main() {
oldLocation := "/var/www/html/test.txt"
newLocation := "/var/www/html/src/test.txt"
err := os.Rename(oldLocation, newLocation)
if err != nil {
log.Fatal(err)
}
}
原创文章,转载请注明出处:
http://30daydo.com/article/44288
  查看全部
golang的内库os里面并没有Move的函数,如果要移动文件可以使用os.Rename
 
package main

import (
"log"
"os"
)

func main() {
oldLocation := "/var/www/html/test.txt"
newLocation := "/var/www/html/src/test.txt"
err := os.Rename(oldLocation, newLocation)
if err != nil {
log.Fatal(err)
}
}

原创文章,转载请注明出处:
http://30daydo.com/article/44288
 

golang:为什么chan关闭了也无法接受到内容呢?

李魔佛 发表了文章 • 0 个评论 • 2117 次浏览 • 2021-11-18 20:12 • 来自相关话题

go代码如下: package main

import "fmt"

func main() {
ch := make(chan int)
ch <- 1
close(ch)
n, ok := <-ch
if !ok {
fmt.Println("Error")
}
fmt.Println(n)
var input string
fmt.Scanln(&input)

实际程序死锁。
 
有人问,chan close后不会可以被读取到了吗?
 
但是实际程序运行到:
ch <- 1
这里, 已经被阻塞,导致报错,无法接下来的close操作。
 
加入打印信息:package main

import "fmt"

func main() {
ch := make(chan int)
fmt.Println("start")
ch <- 1
fmt.Println("next")
close(ch)
n, ok := <-ch
if !ok {
fmt.Println("Error")
}
fmt.Println(n)
var input string
fmt.Scanln(&input)
}
实际只打印到start, next那个已经不输出了。:!go run channel_close.go
start
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
/home/admin/git/GolangLearning/helloworld/channel/channel_close.go:8 +0xa8
exit status 2

shell returned 1
正确的修改:package main

import "fmt"

func main() {
ch := make(chan int)
go func() {
fmt.Println("start")
ch <- 1
fmt.Println("next")
close(ch)
}()
n, ok := <-ch
if !ok {
fmt.Println("Error")
}
fmt.Println(n)
var input string
fmt.Scanln(&input)
}

 
创建了一个免费的Go知识星球社区,欢迎加入一起讨论吧


  查看全部
go代码如下:
   package main                                                                                                                        

import "fmt"

func main() {
ch := make(chan int)
ch <- 1
close(ch)
n, ok := <-ch
if !ok {
fmt.Println("Error")
}
fmt.Println(n)
var input string
fmt.Scanln(&input)
}
 
实际程序死锁。
 
有人问,chan close后不会可以被读取到了吗?
 
但是实际程序运行到:
ch <- 1
这里, 已经被阻塞,导致报错,无法接下来的close操作。
 
加入打印信息:
package main

import "fmt"

func main() {
ch := make(chan int)
fmt.Println("start")
ch <- 1
fmt.Println("next")
close(ch)
n, ok := <-ch
if !ok {
fmt.Println("Error")
}
fmt.Println(n)
var input string
fmt.Scanln(&input)
}

实际只打印到start, next那个已经不输出了。
:!go run channel_close.go                                                                                                               
start
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
/home/admin/git/GolangLearning/helloworld/channel/channel_close.go:8 +0xa8
exit status 2

shell returned 1

正确的修改:
package main

import "fmt"

func main() {
ch := make(chan int)
go func() {
fmt.Println("start")
ch <- 1
fmt.Println("next")
close(ch)
}()
n, ok := <-ch
if !ok {
fmt.Println("Error")
}
fmt.Println(n)
var input string
fmt.Scanln(&input)
}

 
创建了一个免费的Go知识星球社区,欢迎加入一起讨论吧


 

go并发编程实战 汪明 源码 下载

李魔佛 发表了文章 • 0 个评论 • 1949 次浏览 • 2021-11-09 20:19 • 来自相关话题

 

 
源码地址下载:
链接:https://pan.baidu.com/s/1BsUCk55yIUBoZ7Ugj7IXgw 
提取码:v369
 
  查看全部

 

 
源码地址下载:
链接:https://pan.baidu.com/s/1BsUCk55yIUBoZ7Ugj7IXgw 
提取码:v369
 
 

go get 加 -u 和不加 -u 参数的区别

李魔佛 发表了文章 • 0 个评论 • 1957 次浏览 • 2021-11-09 14:44 • 来自相关话题

如果已经下载过一个代码包,但是这个代码包又有更新了,那么这时候可以直接用 -u 标记来更新本地的对应的代码包。
如果不加这个 -u 标记,执行 go get 一个已有的代码包,会发现命令什么都不执行。
 
只有加了 -u 标记,命令会去执行 git pull 命令拉取最新的代码包的最新版本,下载并安装。 查看全部

如果已经下载过一个代码包,但是这个代码包又有更新了,那么这时候可以直接用 -u 标记来更新本地的对应的代码包。
如果不加这个 -u 标记,执行 go get 一个已有的代码包,会发现命令什么都不执行。
 
只有加了 -u 标记,命令会去执行 git pull 命令拉取最新的代码包的最新版本,下载并安装。

golang中chan 无缓冲和 chan有缓冲 长度size设为1的区别

低调的哥哥 发表了文章 • 0 个评论 • 3450 次浏览 • 2021-10-28 09:15 • 来自相关话题

在群里看到有人说没有区别。其实差别还很大的呀
 
无缓冲情况下,一把数据放入chan,如果没有其他协程取数据,接下来的操作是阻塞的
而在size=1的情况下, 第一个数据放入chan后,并不会马上阻塞,接下来的操作还是可以进行的。
 
看下面的代码 f1和f2的区别
 package main

import "time"

func f1() {

ch := make(chan int) // no buffer
go func() {

ch <- 0
println("out of routine")
}()
println("f1 start")
time.Sleep(time.Second * 3)
<-ch
println("End")

}

func f2() {

ch := make(chan int, 1) // size =1
go func() {

ch <- 0
println("out of routine")
}()
println("f1 start")
time.Sleep(time.Second * 3)
<-ch
println("End")

}
func main() {
//f1()
f2()
}
f1 最后不会输出End, 而f2则可以输出f2
 
创建了一个免费的Go知识星球社区,欢迎加入一起讨论吧

  查看全部
在群里看到有人说没有区别。其实差别还很大的呀
 
无缓冲情况下,一把数据放入chan,如果没有其他协程取数据,接下来的操作是阻塞的
而在size=1的情况下, 第一个数据放入chan后,并不会马上阻塞,接下来的操作还是可以进行的。
 
看下面的代码 f1和f2的区别
 
package main

import "time"

func f1() {

ch := make(chan int) // no buffer
go func() {

ch <- 0
println("out of routine")
}()
println("f1 start")
time.Sleep(time.Second * 3)
<-ch
println("End")

}

func f2() {

ch := make(chan int, 1) // size =1
go func() {

ch <- 0
println("out of routine")
}()
println("f1 start")
time.Sleep(time.Second * 3)
<-ch
println("End")

}
func main() {
//f1()
f2()
}

f1 最后不会输出End, 而f2则可以输出f2
 
创建了一个免费的Go知识星球社区,欢迎加入一起讨论吧

 

go中的rand.Int() 为什么每次返回的都是同一个值,并不是随机?

李魔佛 发表了文章 • 0 个评论 • 4797 次浏览 • 2021-10-21 17:38 • 来自相关话题

比如下面的代码:
package main

import "math/rand"

func GenRandom() chan int {
ch := make(chan int, 10)
go func() {
for {
ch <- rand.Int()
}
}()

return ch
}
func main() {
ch := GenRandom()
println(<-ch)
println("end of main")

}
返回的永远都是
5577006791947779410
 
原因是每次没有调用rand.Seed(xxxx), 导致随机种子都是 1 。 见官方文档Seed uses the provided seed value to initialize the default Source to a deterministic state. If Seed is not called, the generator behaves as if seeded by Seed(1).
  
所以如果想要每次随机值不一样
需要用时间戳作为随机种子
 
func GenRandom() chan int {
ch := make(chan int, 10)
go func() {
rand.Seed(time.Now().Unix())
for {
ch <- rand.Intn(200)
}
}()

return ch
} 查看全部
比如下面的代码:
package main

import "math/rand"

func GenRandom() chan int {
ch := make(chan int, 10)
go func() {
for {
ch <- rand.Int()
}
}()

return ch
}
func main() {
ch := GenRandom()
println(<-ch)
println("end of main")

}

返回的永远都是
5577006791947779410
 
原因是每次没有调用rand.Seed(xxxx), 导致随机种子都是 1 。 见官方文档
Seed uses the provided seed value to initialize the default Source to a deterministic state. If Seed is not called, the generator behaves as if seeded by Seed(1).

  
所以如果想要每次随机值不一样
需要用时间戳作为随机种子
 
func GenRandom() chan int {
ch := make(chan int, 10)
go func() {
rand.Seed(time.Now().Unix())
for {
ch <- rand.Intn(200)
}
}()

return ch
}

go env 与go path,go module 的设置

量化大师 发表了文章 • 0 个评论 • 5191 次浏览 • 2021-08-16 16:56 • 来自相关话题

一、GOROOT

GOROOT指的Golang语言的安装路径,即Golang语言内置程序库所在的位置。通常在安装时环境变量会设置好GOROOT路径。当开发时,import标准库时并不需要额外安装,当程序运行后,也会去GOROOT路径下寻找相应程序。

二、GOPATH

GOPATH即存放第三方库的位置。通常开发时,会把GOPATH重新设置。

2.1 GOPATH目录

bin:放置编译后生成的可执行文件。

pkg:放置编译后生成的包/库的归档文件

src:放置项目和库的源文件;

2.1.1 src

用于以包(package)的形式组织并存放 Go 源文件,这里的包与 src 下的每个子目录是一一对应。例如,若一个源文件被声明属于 log 包,那么它就应当保存在 src/log 目录中。

并不是说 src 目录下不能存放 Go 源文件,一般在测试或演示的时候也可以把 Go 源文件直接放在 src目录下,但是这么做的话就只能声明该源文件属于 main 包了。正常开发中还是建议大家把 Go 源文件放入特定的目录中。

另外需要注意的是,Go语言会把通过go get命令获取到的库源文件下载到 src 目录下对应的文件夹当中。

2.1.2 pkg

用于存放通过go install命令安装某个包后的归档文件。归档文件是指那些名称以“.a”结尾的文件。

该目录与 GOROOT 目录(也就是Go语言的安装目录)下的 pkg 目录功能类似,区别在于这里的 pkg 目录专门用来存放项目代码的归档文件。

编译和安装项目代码的过程一般会以代码包为单位进行,比如 log 包被编译安装后,将生成一个名为 log.a 的归档文件,并存放在当前项目的 pkg 目录下。

2.1.3 bin

与 pkg 目录类似,在通过go install命令完成安装后,保存由 Go 命令源文件生成的可执行文件。在类 Unix 操作系统下,这个可执行文件的名称与命令源文件的文件名相同。

而在 Windows 操作系统下,这个可执行文件的名称则是命令源文件的文件名加 .exe 后缀。

2.2 设置和使用GOPATH
2.2.1 windows设置

在环境变量中添加GOPATH变量,将目录添加即可。

2.2.2 linux设置

设置当前目录为GOPATH:选择一个目录,在目录的命令行下执行
export GOPATH='pwd'
 
2.3 GOPATH缺点

只要第三方库不是官方程序库,都要放置到$GOPATH/src下才可以使用.

三 Go Modules

Golang从1.13版本开始有Go Modules.

3.1 使用Go Modules的好处

Go Modules可以将某个项目(文件夹)下的所有依赖整理成一个 go.mod 文件,里面写入了依赖的版本等 使用Go Modules之后我们可不用将代码放置在src下了

3.2 使用Go Modules

官方github关于Modules的WIKI:https://github.com/golang/go/wiki/Modules 
使用 Go Modules 管理依赖后会在项目根目录下生成两个文件 go.mod 和 go.sum go.mod会记录当前项目的所有依赖项module test go 1.15 require http://github.com/gin-gonic/gin v1.6.3go.sum
会记录每个依赖库的版本和哈希值
 
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=3.3 如何开启Go Modules


要使用Go Modules首先要设置Go111Modules = on, GO111MODULE有三个值 on:开启 off:关闭 auto根据当前目录下是否有go.mod文件来判断是否使用modules功能

注意:**无论使用那种模式,module功能默认不在GOPATH目录下查找依赖文件,所以使用modules功能时请设置好代理

设置
GO111MODULE
# windows set GO111MODULE=on 
# linux export GO111MODULE=on
然后使用go env查看

3.4 初始化Go Modules进入项目文件夹test 
# 初始化路径 go mod init test 
# 检测依赖 go mod tidy 
# 如果有些依赖项未下载则需要下载 go mod download 
# 导入依赖 go mod vendor3.5 GoLand开启Go Modules

文件(File) 设置(Setting) 在GO选项下选择GO MODULES 启用Go Modules 设置代理服务器

3.6 更新依赖# 检测依赖 go mod tidy # 如果有些依赖项未下载则需要下载 go mod download # 导入依赖 go mod vendor3.7 Git使用GO MODULES注意事项

在git中需要把vendor文件夹放入白名单中,不然项目体积会很大。 git设置白名单方式为在git托管的项目根目录新建 .gitignore 文件,设置忽略即可,但是 go.mod 和 go.sum 不要忽略。 
另一人clone项目后在本地进行依赖更新(同上方依赖更新)即可

3.8 Go Module常用命令go mod init 
# 初始化go.mod go mod tidy 
# 更新依赖文件 go mod download 
# 下载依赖文件 go mod vendor 
# 将依赖转移至本地的vendor文件 go mod edit 
# 手动修改依赖文件 go mod graph 
# 打印依赖图 go mod verify 
# 校验依赖 go mod why 
# 解释为什么需要依赖四、GO PROXY

GOPROXY 是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置环境变量 GOPROXY 即可。

4.1 国内镜像

// 阿里云镜像

GOPROXY=https://mirrors.aliyun.com/goproxy/ // 中国golang镜像

GOPROXY=https://goproxy.io

// 七牛云为中国的gopher提供了一个免费合法的代理goproxy.cn,其已经开源。只需一条简单命令就可以使用该代理:go env -w GOPROXY=https://goproxy.cn,direct五、Go Get

执行go get命令,在下载依赖包的同时还可以指定依赖包的版本。

运行go get -u命令会将项目中的包升级到最新的次要版本或者修订版本;

运行go get -u=patch命令会将项目中的包升级到最新的修订版本;

运行go get [包名]@[版本号]命令会下载对应包的指定版本或者将对应包升级到指定的版本。

提示:go get [包名]@[版本号]命令中版本号可以是 x.y.z 的形式,

例如 go get foo@v1.2.3,也可以是 git 上的分支或 tag,例如 go get foo@master,还可以是 git 提交时的哈希值,例如 go get foo@e3702bed2。

六、godep

godep 是一个Go语言官方提供的通过 vender 模式来管理第三方依赖的工具,类似的还有由社区维护的准官方包管理工具 dep。

Go语言从 1.5 版本开始开始引入 vendor 模式,如果项目目录下有 vendor 目录,那么Go语言编译器会优先使用 vendor 内的包进行编译、测试等。

6.1 安装godepgo get github.com/tools/godep命令执行成功后会将 godep 工具的源码下载到 GOPATH 的 src 录下对应的文件夹中,同时还会在 GOPATH 的 bin 目录下生成一个名为 godep.exe 的可执行文件。

6.2 配置环境变量


6.3 godep基本命令

命令 说明godep save 将依赖包的信息保存到Godeps.json文件中 godep go 使用保存的依赖项运行go工具 godep get 下载并安装指定的包 godep path 打印依赖的GOPATH路径 godep restore 在GOPATH中拉取依赖的版本 godep update 更新选定的包或go版本 godep diff 显示当前和以前保存的依赖项集之间的差异 godep version 查看版本信息6.4 使用godep

执行godep save命令,会在当前目录中创建 Godeps 和 vender 两个文件夹。

Godeps 文件夹下会生成一个 Godeps.json 文件,用来记录项目中所依赖的包信息;vender 目录则是用来保存当前项目所依赖的所有第三方包。生成的 Godeps.json 文件的结构如下所示:{
"ImportPath": "main",//项目路径信息
"GoVersion": "go1.13",//go语言版本号
"GodepVersion": "v80",//godep版本号
"Deps": [//当前引用的包
{
"ImportPath": "github.com/go-gomail/gomail",//依赖包路径
"Comment": "2.0.0-23-g81ebce5",//版本号
"Rev": "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1"//哈希值
}
]
}
当所引用的第三方包要升级只需要修改Godep.json里面的依赖包的版本号,让后执行godep save命令即可。

godep查找依赖顺序: 在项目路径下的vender文件夹中查找 到GOPATH/src目录查找 查看全部
一、GOROOT

GOROOT指的Golang语言的安装路径,即Golang语言内置程序库所在的位置。通常在安装时环境变量会设置好GOROOT路径。当开发时,import标准库时并不需要额外安装,当程序运行后,也会去GOROOT路径下寻找相应程序。

二、GOPATH

GOPATH即存放第三方库的位置。通常开发时,会把GOPATH重新设置。

2.1 GOPATH目录

bin:放置编译后生成的可执行文件。

pkg:放置编译后生成的包/库的归档文件

src:放置项目和库的源文件;

2.1.1 src

用于以包(package)的形式组织并存放 Go 源文件,这里的包与 src 下的每个子目录是一一对应。例如,若一个源文件被声明属于 log 包,那么它就应当保存在 src/log 目录中。

并不是说 src 目录下不能存放 Go 源文件,一般在测试或演示的时候也可以把 Go 源文件直接放在 src目录下,但是这么做的话就只能声明该源文件属于 main 包了。正常开发中还是建议大家把 Go 源文件放入特定的目录中。

另外需要注意的是,Go语言会把通过go get命令获取到的库源文件下载到 src 目录下对应的文件夹当中。

2.1.2 pkg

用于存放通过go install命令安装某个包后的归档文件。归档文件是指那些名称以“.a”结尾的文件。

该目录与 GOROOT 目录(也就是Go语言的安装目录)下的 pkg 目录功能类似,区别在于这里的 pkg 目录专门用来存放项目代码的归档文件。

编译和安装项目代码的过程一般会以代码包为单位进行,比如 log 包被编译安装后,将生成一个名为 log.a 的归档文件,并存放在当前项目的 pkg 目录下。

2.1.3 bin

与 pkg 目录类似,在通过go install命令完成安装后,保存由 Go 命令源文件生成的可执行文件。在类 Unix 操作系统下,这个可执行文件的名称与命令源文件的文件名相同。

而在 Windows 操作系统下,这个可执行文件的名称则是命令源文件的文件名加 .exe 后缀。

2.2 设置和使用GOPATH
2.2.1 windows设置

在环境变量中添加GOPATH变量,将目录添加即可。

2.2.2 linux设置

设置当前目录为GOPATH:选择一个目录,在目录的命令行下执行
export GOPATH='pwd'
 
2.3 GOPATH缺点

只要第三方库不是官方程序库,都要放置到$GOPATH/src下才可以使用.

三 Go Modules

Golang从1.13版本开始有Go Modules.

3.1 使用Go Modules的好处

Go Modules可以将某个项目(文件夹)下的所有依赖整理成一个 go.mod 文件,里面写入了依赖的版本等 使用Go Modules之后我们可不用将代码放置在src下了

3.2 使用Go Modules

官方github关于Modules的WIKI:https://github.com/golang/go/wiki/Modules 
使用 Go Modules 管理依赖后会在项目根目录下生成两个文件 go.mod 和 go.sum go.mod会记录当前项目的所有依赖项module test go 1.15 require http://github.com/gin-gonic/gin v1.6.3go.sum
会记录每个依赖库的版本和哈希值
 
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=3.3 如何开启Go Modules


要使用Go Modules首先要设置Go111Modules = on, GO111MODULE有三个值 on:开启 off:关闭 auto根据当前目录下是否有go.mod文件来判断是否使用modules功能

注意:**无论使用那种模式,module功能默认不在GOPATH目录下查找依赖文件,所以使用modules功能时请设置好代理

设置
GO111MODULE
# windows set GO111MODULE=on 
# linux export GO111MODULE=on
然后使用go env查看

3.4 初始化Go Modules进入项目文件夹test 
# 初始化路径 go mod init test 
# 检测依赖 go mod tidy 
# 如果有些依赖项未下载则需要下载 go mod download 
# 导入依赖 go mod vendor3.5 GoLand开启Go Modules

文件(File) 设置(Setting) 在GO选项下选择GO MODULES 启用Go Modules 设置代理服务器

3.6 更新依赖# 检测依赖 go mod tidy # 如果有些依赖项未下载则需要下载 go mod download # 导入依赖 go mod vendor3.7 Git使用GO MODULES注意事项

在git中需要把vendor文件夹放入白名单中,不然项目体积会很大。 git设置白名单方式为在git托管的项目根目录新建 .gitignore 文件,设置忽略即可,但是 go.mod 和 go.sum 不要忽略。 
另一人clone项目后在本地进行依赖更新(同上方依赖更新)即可

3.8 Go Module常用命令go mod init 
# 初始化go.mod go mod tidy 
# 更新依赖文件 go mod download 
# 下载依赖文件 go mod vendor 
# 将依赖转移至本地的vendor文件 go mod edit 
# 手动修改依赖文件 go mod graph 
# 打印依赖图 go mod verify 
# 校验依赖 go mod why 
# 解释为什么需要依赖四、GO PROXY

GOPROXY 是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置环境变量 GOPROXY 即可。

4.1 国内镜像

// 阿里云镜像

GOPROXY=https://mirrors.aliyun.com/goproxy/ // 中国golang镜像

GOPROXY=https://goproxy.io

// 七牛云为中国的gopher提供了一个免费合法的代理goproxy.cn,其已经开源。只需一条简单命令就可以使用该代理:go env -w GOPROXY=https://goproxy.cn,direct五、Go Get

执行go get命令,在下载依赖包的同时还可以指定依赖包的版本。

运行go get -u命令会将项目中的包升级到最新的次要版本或者修订版本;

运行go get -u=patch命令会将项目中的包升级到最新的修订版本;

运行go get [包名]@[版本号]命令会下载对应包的指定版本或者将对应包升级到指定的版本。

提示:go get [包名]@[版本号]命令中版本号可以是 x.y.z 的形式,

例如 go get foo@v1.2.3,也可以是 git 上的分支或 tag,例如 go get foo@master,还可以是 git 提交时的哈希值,例如 go get foo@e3702bed2。

六、godep

godep 是一个Go语言官方提供的通过 vender 模式来管理第三方依赖的工具,类似的还有由社区维护的准官方包管理工具 dep。

Go语言从 1.5 版本开始开始引入 vendor 模式,如果项目目录下有 vendor 目录,那么Go语言编译器会优先使用 vendor 内的包进行编译、测试等。

6.1 安装godepgo get github.com/tools/godep命令执行成功后会将 godep 工具的源码下载到 GOPATH 的 src 录下对应的文件夹中,同时还会在 GOPATH 的 bin 目录下生成一个名为 godep.exe 的可执行文件。

6.2 配置环境变量


6.3 godep基本命令

命令 说明godep save 将依赖包的信息保存到Godeps.json文件中 godep go 使用保存的依赖项运行go工具 godep get 下载并安装指定的包 godep path 打印依赖的GOPATH路径 godep restore 在GOPATH中拉取依赖的版本 godep update 更新选定的包或go版本 godep diff 显示当前和以前保存的依赖项集之间的差异 godep version 查看版本信息6.4 使用godep

执行godep save命令,会在当前目录中创建 Godeps 和 vender 两个文件夹。

Godeps 文件夹下会生成一个 Godeps.json 文件,用来记录项目中所依赖的包信息;vender 目录则是用来保存当前项目所依赖的所有第三方包。生成的 Godeps.json 文件的结构如下所示:
{
"ImportPath": "main",//项目路径信息
"GoVersion": "go1.13",//go语言版本号
"GodepVersion": "v80",//godep版本号
"Deps": [//当前引用的包
{
"ImportPath": "github.com/go-gomail/gomail",//依赖包路径
"Comment": "2.0.0-23-g81ebce5",//版本号
"Rev": "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1"//哈希值
}
]
}

当所引用的第三方包要升级只需要修改Godep.json里面的依赖包的版本号,让后执行godep save命令即可。

godep查找依赖顺序: 在项目路径下的vender文件夹中查找 到GOPATH/src目录查找