golang

golang

golang mysql count(*) 的写法

Golang马化云 发表了文章 • 0 个评论 • 303 次浏览 • 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操作 保存这篇文章就足够了)

Golang马化云 发表了文章 • 0 个评论 • 347 次浏览 • 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 集合,并判断元素是否存在

Golang李魔佛 发表了文章 • 0 个评论 • 672 次浏览 • 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

Golang李魔佛 发表了文章 • 0 个评论 • 683 次浏览 • 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 前端与后端的正确写法

Golang李魔佛 发表了文章 • 0 个评论 • 1017 次浏览 • 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应用 无法下载第三方包 解决办法

Golang李魔佛 发表了文章 • 0 个评论 • 989 次浏览 • 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

 

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

Golang李魔佛 发表了文章 • 0 个评论 • 940 次浏览 • 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,否则弄得系统一堆依赖问题。

REST ful API的规范 delete方法不建议在body放入数据

网络李魔佛 发表了文章 • 0 个评论 • 1161 次浏览 • 2021-12-27 14:58 • 来自相关话题

毕竟delete参数是根据uri删除资源.
 
因为资源的唯一性,所以就没必要再在body里面放入其他的数据了.
 
什么? 通过uri不能确定资源的唯一? 那么你这个设计就不是REST规范了.
 
那PUT这些操作也无法准确更新资源了.
毕竟delete参数是根据uri删除资源.
 
因为资源的唯一性,所以就没必要再在body里面放入其他的数据了.
 
什么? 通过uri不能确定资源的唯一? 那么你这个设计就不是REST规范了.
 
那PUT这些操作也无法准确更新资源了.

golang的时间格式化 做法有点像格力手机的开机画面是董小姐

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

网络上的开发者基本都是一路吐槽。
 
过去用java,python,php,等语言,将一个时间格式化成一个字符串都是用“yyy-MM-dd hh:mm:ss”之类的方法,golang 的格式化方法真令我大开眼界

先看官方文档说明:

func (Time) Format
func (t Time) Format(layout string) string
Format returns a textual representation of the time value formatted according to layout, which defines the format by showing how the reference time, defined to be

Mon Jan 2 15:04:05 -0700 MST 2006
would be displayed if it were the value; it serves as an example of the desired output. The same display rules will then be applied to the time value. Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard and convenient representations of the reference time. For more information about the formats and the definition of the reference time, see the documentation for ANSIC and the other constants defined by this package.


下面给个代码:

fmt.Println(time.Now().Format("2006-01-02 150405"))

要注意那时间,只能是2006-01-02 15:04:05分,其它的时间都不行,真是够绝。
 做法有点像格力手机的开机画面是董小姐。
用个语言还得记住你golang的生日?? 查看全部
网络上的开发者基本都是一路吐槽。
 
过去用java,python,php,等语言,将一个时间格式化成一个字符串都是用“yyy-MM-dd hh:mm:ss”之类的方法,golang 的格式化方法真令我大开眼界

先看官方文档说明:

func (Time) Format
func (t Time) Format(layout string) string
Format returns a textual representation of the time value formatted according to layout, which defines the format by showing how the reference time, defined to be

Mon Jan 2 15:04:05 -0700 MST 2006
would be displayed if it were the value; it serves as an example of the desired output. The same display rules will then be applied to the time value. Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard and convenient representations of the reference time. For more information about the formats and the definition of the reference time, see the documentation for ANSIC and the other constants defined by this package.


下面给个代码:

fmt.Println(time.Now().Format("2006-01-02 150405"))

要注意那时间,只能是2006-01-02 15:04:05分,其它的时间都不行,真是够绝。

 做法有点像格力手机的开机画面是董小姐。
用个语言还得记住你golang的生日??

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

Golang李魔佛 发表了文章 • 0 个评论 • 1130 次浏览 • 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映射的时候可以适配大小写。
 

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

Golang李魔佛 发表了文章 • 0 个评论 • 986 次浏览 • 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

Golang李魔佛 发表了文章 • 0 个评论 • 908 次浏览 • 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

Golang马化云 发表了文章 • 0 个评论 • 992 次浏览 • 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 ?

Golang李魔佛 发表了文章 • 0 个评论 • 1074 次浏览 • 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

Golang李魔佛 发表了文章 • 0 个评论 • 1558 次浏览 • 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
 

golang mysql count(*) 的写法

Golang马化云 发表了文章 • 0 个评论 • 303 次浏览 • 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操作 保存这篇文章就足够了)

Golang马化云 发表了文章 • 0 个评论 • 347 次浏览 • 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 集合,并判断元素是否存在

Golang李魔佛 发表了文章 • 0 个评论 • 672 次浏览 • 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

Golang李魔佛 发表了文章 • 0 个评论 • 683 次浏览 • 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 前端与后端的正确写法

Golang李魔佛 发表了文章 • 0 个评论 • 1017 次浏览 • 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应用 无法下载第三方包 解决办法

Golang李魔佛 发表了文章 • 0 个评论 • 989 次浏览 • 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

 

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

Golang李魔佛 发表了文章 • 0 个评论 • 940 次浏览 • 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,否则弄得系统一堆依赖问题。

REST ful API的规范 delete方法不建议在body放入数据

网络李魔佛 发表了文章 • 0 个评论 • 1161 次浏览 • 2021-12-27 14:58 • 来自相关话题

毕竟delete参数是根据uri删除资源.
 
因为资源的唯一性,所以就没必要再在body里面放入其他的数据了.
 
什么? 通过uri不能确定资源的唯一? 那么你这个设计就不是REST规范了.
 
那PUT这些操作也无法准确更新资源了.
毕竟delete参数是根据uri删除资源.
 
因为资源的唯一性,所以就没必要再在body里面放入其他的数据了.
 
什么? 通过uri不能确定资源的唯一? 那么你这个设计就不是REST规范了.
 
那PUT这些操作也无法准确更新资源了.

golang的时间格式化 做法有点像格力手机的开机画面是董小姐

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

网络上的开发者基本都是一路吐槽。
 
过去用java,python,php,等语言,将一个时间格式化成一个字符串都是用“yyy-MM-dd hh:mm:ss”之类的方法,golang 的格式化方法真令我大开眼界

先看官方文档说明:

func (Time) Format
func (t Time) Format(layout string) string
Format returns a textual representation of the time value formatted according to layout, which defines the format by showing how the reference time, defined to be

Mon Jan 2 15:04:05 -0700 MST 2006
would be displayed if it were the value; it serves as an example of the desired output. The same display rules will then be applied to the time value. Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard and convenient representations of the reference time. For more information about the formats and the definition of the reference time, see the documentation for ANSIC and the other constants defined by this package.


下面给个代码:

fmt.Println(time.Now().Format("2006-01-02 150405"))

要注意那时间,只能是2006-01-02 15:04:05分,其它的时间都不行,真是够绝。
 做法有点像格力手机的开机画面是董小姐。
用个语言还得记住你golang的生日?? 查看全部
网络上的开发者基本都是一路吐槽。
 
过去用java,python,php,等语言,将一个时间格式化成一个字符串都是用“yyy-MM-dd hh:mm:ss”之类的方法,golang 的格式化方法真令我大开眼界

先看官方文档说明:

func (Time) Format
func (t Time) Format(layout string) string
Format returns a textual representation of the time value formatted according to layout, which defines the format by showing how the reference time, defined to be

Mon Jan 2 15:04:05 -0700 MST 2006
would be displayed if it were the value; it serves as an example of the desired output. The same display rules will then be applied to the time value. Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard and convenient representations of the reference time. For more information about the formats and the definition of the reference time, see the documentation for ANSIC and the other constants defined by this package.


下面给个代码:

fmt.Println(time.Now().Format("2006-01-02 150405"))

要注意那时间,只能是2006-01-02 15:04:05分,其它的时间都不行,真是够绝。

 做法有点像格力手机的开机画面是董小姐。
用个语言还得记住你golang的生日??

30天学会Golang

Golang马化云 发表了文章 • 0 个评论 • 992 次浏览 • 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 ?

Golang李魔佛 发表了文章 • 0 个评论 • 1074 次浏览 • 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

Golang李魔佛 发表了文章 • 0 个评论 • 1558 次浏览 • 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

Golang李魔佛 发表了文章 • 0 个评论 • 870 次浏览 • 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文件操作之 移动文件

Golang李魔佛 发表了文章 • 0 个评论 • 2638 次浏览 • 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关闭了也无法接受到内容呢?

Golang李魔佛 发表了文章 • 0 个评论 • 1041 次浏览 • 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知识星球社区,欢迎加入一起讨论吧