mirror of
https://gitee.com/johng/gf
synced 2026-06-09 19:13:58 +08:00
Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 671157cb70 | |||
| f775479c3f | |||
| 64bb72842e | |||
| e1d4ba9d23 | |||
| a1edd83add | |||
| f7d6883405 | |||
| 8448a70646 | |||
| 4018bfa899 | |||
| 3cc9ce74e1 | |||
| eac60d845f | |||
| 835c045c92 | |||
| be15f85eae | |||
| 3e27ea0259 | |||
| 6abe660287 | |||
| a06ca31530 | |||
| 890865251b | |||
| 6af90cafee | |||
| 2e2363bb41 | |||
| 108ced2b0b | |||
| fcba650348 | |||
| 1b8a082942 | |||
| 40570cdb03 | |||
| 10451864e6 | |||
| 55e2646367 | |||
| c88839edb1 | |||
| 2a2cfc289c | |||
| 8bbeb186c2 | |||
| be4bf39719 | |||
| 459c69839a | |||
| a5407e57d9 | |||
| 5c749e7762 | |||
| b3fafc64f8 | |||
| c7b0763ab0 | |||
| 0cfdf60de5 | |||
| 096bff791d | |||
| 0cce858641 | |||
| bb45d8d578 | |||
| 7e43aa6b9d | |||
| 4ee7c82bf1 | |||
| 85caa40a3d | |||
| f4654bf446 | |||
| 94ed0bf9c9 | |||
| 22e3705d3e | |||
| 9b1cc6e9c7 | |||
| 9429c8ff83 | |||
| 056c6d4688 | |||
| 382356bc8d | |||
| 1deb3510f0 | |||
| dd7ae1b07a | |||
| 04a8755162 | |||
| 682f99a763 | |||
| 61282d6dab | |||
| ad540f7c25 | |||
| a4f191c1c6 | |||
| 43531c2680 | |||
| 635f5d36fd | |||
| 1becc4932c | |||
| e36dd06f22 | |||
| 8f2c62d444 | |||
| 21efde1a38 | |||
| d8b6466ed0 | |||
| d7b0228e9e | |||
| 9da1277b47 | |||
| a3fd0c9a4a | |||
| ad7375b44b | |||
| 05120b585d | |||
| 9e32d74c8c | |||
| 0e62510c6f | |||
| c492de4fa8 | |||
| 6308380541 | |||
| 2609db1aec | |||
| 6c54e73dbd | |||
| 21abe62633 | |||
| e30b2b0732 | |||
| dcb74ee9df | |||
| 82bf21e831 | |||
| 66355354fc | |||
| 4204125dce | |||
| e6aa9d3a46 | |||
| 9416cd1274 | |||
| 8b5ab846b2 | |||
| a15b93be90 | |||
| 38ee5f7d53 | |||
| 6f9bbbf416 | |||
| 143bc3d8e3 | |||
| ea75b1a936 | |||
| 0dde8c735e | |||
| 1ab7f00b91 | |||
| 3ef42bfbf0 | |||
| 05fec23457 | |||
| 7225e49aa0 | |||
| 14e9deb254 | |||
| f9569b387f | |||
| a0722ed51f | |||
| e9ace9b17a | |||
| 4791d10761 | |||
| c686b1c080 | |||
| 056d6ebbd9 | |||
| baa2cb68de | |||
| e4909b318b | |||
| f1b7cb37c6 | |||
| 734728fa9c | |||
| b373ace065 | |||
| bc7b5c8626 | |||
| f2b45622d6 | |||
| 77cb219057 | |||
| cf34d7bd56 | |||
| 5adc9be0d9 | |||
| 58b2efc900 | |||
| 28326606f5 | |||
| 91c98bbb60 | |||
| 63cd1128a7 | |||
| c0236d7dfa | |||
| d4051df5b6 | |||
| 88045417ff | |||
| 500efb5601 | |||
| 97fe8235da | |||
| e1164e935b | |||
| b26330aee1 | |||
| 2b083709b5 | |||
| 0ac45dc379 | |||
| 650916c22a | |||
| 2804183325 | |||
| cce8ac5118 | |||
| 419b58452f | |||
| b1835ea4e8 |
@ -9,7 +9,7 @@ import (
|
||||
func main() {
|
||||
// 创建一个默认的gmap对象,
|
||||
// 默认情况下该gmap对象不支持并发安全特性,
|
||||
// 初始化时可以给定true参数关闭并发安全特性,当做一个普通的map使用。
|
||||
// 初始化时可以给定true参数开启并发安全特性,用以并发安全场景。
|
||||
m := gmap.New()
|
||||
|
||||
// 设置键值对
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := gmap.New()
|
||||
m1 := gmap.New(true)
|
||||
m1.Set("1", "1")
|
||||
|
||||
m2 := m1.Map()
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
|
||||
|
||||
#[database]
|
||||
# [[database.default]]
|
||||
# type = "mysql"
|
||||
# link = "root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
37
.example/database/gdb/mysql/config/gdb.go
Normal file
37
.example/database/gdb/mysql/config/gdb.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var db gdb.DB
|
||||
|
||||
func init() {
|
||||
gdb.AddDefaultConfigNode(gdb.ConfigNode{
|
||||
Host: "127.0.0.1",
|
||||
Port: "3306",
|
||||
User: "root",
|
||||
Pass: "12345678",
|
||||
Name: "test",
|
||||
Type: "mysql",
|
||||
Role: "master",
|
||||
Charset: "utf8",
|
||||
MaxOpenConnCount: 100,
|
||||
})
|
||||
db, _ = gdb.New()
|
||||
}
|
||||
|
||||
func main() {
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < 100000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
time.Sleep(10 * time.Second)
|
||||
db.Table("user").Where("id=1").All()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
@ -1,533 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
// 本文件用于gf框架的mysql数据库操作示例,不作为单元测试使用
|
||||
|
||||
var db gdb.DB
|
||||
|
||||
// 初始化配置及创建数据库
|
||||
func init() {
|
||||
gdb.AddDefaultConfigNode(gdb.ConfigNode{
|
||||
Host: "127.0.0.1",
|
||||
Port: "3306",
|
||||
User: "root",
|
||||
Pass: "12345678",
|
||||
Name: "test",
|
||||
Type: "mysql",
|
||||
Role: "master",
|
||||
Charset: "utf8",
|
||||
})
|
||||
db, _ = gdb.New()
|
||||
|
||||
//gins.Config().SetPath("/home/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/frame")
|
||||
//db = g.Database()
|
||||
|
||||
//gdb.SetConfig(gdb.ConfigNode {
|
||||
// Host : "127.0.0.1",
|
||||
// Port : 3306,
|
||||
// User : "root",
|
||||
// Pass : "123456",
|
||||
// Name : "test",
|
||||
// Type : "mysql",
|
||||
//})
|
||||
//db, _ = gdb.Instance()
|
||||
|
||||
//gdb.SetConfig(gdb.Config {
|
||||
// "default" : gdb.ConfigGroup {
|
||||
// gdb.ConfigNode {
|
||||
// Host : "127.0.0.1",
|
||||
// Port : "3306",
|
||||
// User : "root",
|
||||
// Pass : "123456",
|
||||
// Name : "test",
|
||||
// Type : "mysql",
|
||||
// Role : "master",
|
||||
// Weight : 100,
|
||||
// },
|
||||
// gdb.ConfigNode {
|
||||
// Host : "127.0.0.2",
|
||||
// Port : "3306",
|
||||
// User : "root",
|
||||
// Pass : "123456",
|
||||
// Name : "test",
|
||||
// Type : "mysql",
|
||||
// Role : "master",
|
||||
// Weight : 100,
|
||||
// },
|
||||
// gdb.ConfigNode {
|
||||
// Host : "127.0.0.3",
|
||||
// Port : "3306",
|
||||
// User : "root",
|
||||
// Pass : "123456",
|
||||
// Name : "test",
|
||||
// Type : "mysql",
|
||||
// Role : "master",
|
||||
// Weight : 100,
|
||||
// },
|
||||
// gdb.ConfigNode {
|
||||
// Host : "127.0.0.4",
|
||||
// Port : "3306",
|
||||
// User : "root",
|
||||
// Pass : "123456",
|
||||
// Name : "test",
|
||||
// Type : "mysql",
|
||||
// Role : "master",
|
||||
// Weight : 100,
|
||||
// },
|
||||
// },
|
||||
//})
|
||||
//db, _ = gdb.Instance()
|
||||
}
|
||||
|
||||
// 创建测试数据库
|
||||
func create() {
|
||||
fmt.Println("create:")
|
||||
_, err := db.Exec("CREATE DATABASE IF NOT EXISTS test")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
s := `
|
||||
CREATE TABLE IF NOT EXISTS user (
|
||||
uid INT(10) UNSIGNED AUTO_INCREMENT,
|
||||
name VARCHAR(45),
|
||||
PRIMARY KEY (uid)
|
||||
)
|
||||
ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET = utf8
|
||||
`
|
||||
_, err = db.Exec(s)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
s = `
|
||||
CREATE TABLE IF NOT EXISTS user_detail (
|
||||
uid INT(10) UNSIGNED AUTO_INCREMENT,
|
||||
site VARCHAR(255),
|
||||
PRIMARY KEY (uid)
|
||||
)
|
||||
ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET = utf8
|
||||
`
|
||||
|
||||
_, err = db.Exec(s)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 数据写入
|
||||
func insert() {
|
||||
fmt.Println("insert:")
|
||||
r, err := db.Insert("user", gdb.Map{
|
||||
"name": "john",
|
||||
})
|
||||
if err == nil {
|
||||
uid, err2 := r.LastInsertId()
|
||||
if err2 == nil {
|
||||
r, err = db.Insert("user_detail", gdb.Map{
|
||||
"uid": uid,
|
||||
"site": "http://johng.cn",
|
||||
})
|
||||
if err == nil {
|
||||
fmt.Printf("uid: %d\n", uid)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(err2)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 基本sql查询
|
||||
func query() {
|
||||
fmt.Println("query:")
|
||||
list, err := db.GetAll("select * from user limit 2")
|
||||
if err == nil {
|
||||
fmt.Println(list)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// replace into
|
||||
func replace() {
|
||||
fmt.Println("replace:")
|
||||
r, err := db.Save("user", gdb.Map{
|
||||
"uid": 1,
|
||||
"name": "john",
|
||||
})
|
||||
if err == nil {
|
||||
fmt.Println(r.LastInsertId())
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 数据保存
|
||||
func save() {
|
||||
fmt.Println("save:")
|
||||
r, err := db.Save("user", gdb.Map{
|
||||
"uid": 1,
|
||||
"name": "john",
|
||||
})
|
||||
if err == nil {
|
||||
fmt.Println(r.LastInsertId())
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 批量写入
|
||||
func batchInsert() {
|
||||
fmt.Println("batchInsert:")
|
||||
_, err := db.BatchInsert("user", gdb.List{
|
||||
{"name": "john_1"},
|
||||
{"name": "john_2"},
|
||||
{"name": "john_3"},
|
||||
{"name": "john_4"},
|
||||
}, 10)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 数据更新
|
||||
func update1() {
|
||||
fmt.Println("update1:")
|
||||
r, err := db.Update("user", gdb.Map{"name": "john1"}, "uid=?", 1)
|
||||
if err == nil {
|
||||
fmt.Println(r.LastInsertId())
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 数据更新
|
||||
func update2() {
|
||||
fmt.Println("update2:")
|
||||
r, err := db.Update("user", gdb.Map{"name": "john6"}, "uid=?", 1)
|
||||
if err == nil {
|
||||
fmt.Println(r.LastInsertId())
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 数据更新
|
||||
func update3() {
|
||||
fmt.Println("update3:")
|
||||
r, err := db.Update("user", "name=?", "uid=?", "john2", 1)
|
||||
if err == nil {
|
||||
fmt.Println(r.LastInsertId())
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式查询操作1
|
||||
func linkopSelect1() {
|
||||
fmt.Println("linkopSelect1:")
|
||||
r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*, ud.site").Where("u.uid > ?", 1).Limit(0, 2).Select()
|
||||
if err == nil {
|
||||
fmt.Println(r)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式查询操作2
|
||||
func linkopSelect2() {
|
||||
fmt.Println("linkopSelect2:")
|
||||
r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid=?", 1).One()
|
||||
if err == nil {
|
||||
fmt.Println(r)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式查询操作3
|
||||
func linkopSelect3() {
|
||||
fmt.Println("linkopSelect3:")
|
||||
r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("ud.site").Where("u.uid=?", 1).Value()
|
||||
if err == nil {
|
||||
fmt.Println(r.String())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式查询数量1
|
||||
func linkopCount1() {
|
||||
fmt.Println("linkopCount1:")
|
||||
r, err := db.Table("user u").Fields("uid").LeftJoin("user_detail ud", "u.uid=ud.uid").Where("u.uid=?", 1).Count()
|
||||
if err == nil {
|
||||
fmt.Println(r)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 错误操作
|
||||
func linkopUpdate1() {
|
||||
fmt.Println("linkopUpdate1:")
|
||||
r, err := db.Table("henghe_setting").Update()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 通过Map指针方式传参方式
|
||||
func linkopUpdate2() {
|
||||
fmt.Println("linkopUpdate2:")
|
||||
r, err := db.Table("user").Data(gdb.Map{"name": "john2"}).Where("name=?", "john_1").Update()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 通过字符串方式传参
|
||||
func linkopUpdate3() {
|
||||
fmt.Println("linkopUpdate3:")
|
||||
r, err := db.Table("user").Data("name='john3'").Where("name=?", "john2").Update()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Where条件使用Map
|
||||
func linkopUpdate4() {
|
||||
fmt.Println("linkopUpdate4:")
|
||||
r, err := db.Table("user").Data(gdb.Map{"name": "john11111"}).Where(g.Map{"uid": 1}).Update()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式批量写入
|
||||
func linkopBatchInsert1() {
|
||||
fmt.Println("linkopBatchInsert1:")
|
||||
r, err := db.Table("user").Data(gdb.List{
|
||||
{"name": "john_1"},
|
||||
{"name": "john_2"},
|
||||
{"name": "john_3"},
|
||||
{"name": "john_4"},
|
||||
}).Insert()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式批量写入,指定每批次写入的条数
|
||||
func linkopBatchInsert2() {
|
||||
fmt.Println("linkopBatchInsert2:")
|
||||
r, err := db.Table("user").Data(gdb.List{
|
||||
{"name": "john_1"},
|
||||
{"name": "john_2"},
|
||||
{"name": "john_3"},
|
||||
{"name": "john_4"},
|
||||
}).Batch(2).Insert()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 链式批量保存
|
||||
func linkopBatchSave() {
|
||||
fmt.Println("linkopBatchSave:")
|
||||
r, err := db.Table("user").Data(gdb.List{
|
||||
{"uid": 1, "name": "john_1"},
|
||||
{"uid": 2, "name": "john_2"},
|
||||
{"uid": 3, "name": "john_3"},
|
||||
{"uid": 4, "name": "john_4"},
|
||||
}).Save()
|
||||
if err == nil {
|
||||
fmt.Println(r.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 事务操作示例1
|
||||
func transaction1() {
|
||||
fmt.Println("transaction1:")
|
||||
if tx, err := db.Begin(); err == nil {
|
||||
r, err := tx.Save("user", gdb.Map{
|
||||
"uid": 1,
|
||||
"name": "john",
|
||||
})
|
||||
tx.Rollback()
|
||||
fmt.Println(r, err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 事务操作示例2
|
||||
func transaction2() {
|
||||
fmt.Println("transaction2:")
|
||||
if tx, err := db.Begin(); err == nil {
|
||||
r, err := tx.Table("user").Data(gdb.Map{"uid": 1, "name": "john_1"}).Save()
|
||||
tx.Commit()
|
||||
fmt.Println(r, err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 主从io复用测试,在mysql中使用 show full processlist 查看链接信息
|
||||
func keepPing() {
|
||||
fmt.Println("keepPing:")
|
||||
for {
|
||||
fmt.Println("ping...")
|
||||
err := db.PingMaster()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
err = db.PingSlave()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// like语句查询
|
||||
func likeQuery() {
|
||||
fmt.Println("likeQuery:")
|
||||
if r, err := db.Table("user").Where("name like ?", "%john%").Select(); err == nil {
|
||||
fmt.Println(r)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// mapToStruct
|
||||
func mapToStruct() {
|
||||
type User struct {
|
||||
Uid int
|
||||
Name string
|
||||
}
|
||||
fmt.Println("mapToStruct:")
|
||||
if r, err := db.Table("user").Where("uid=?", 1).One(); err == nil {
|
||||
u := User{}
|
||||
if err := r.ToStruct(&u); err == nil {
|
||||
fmt.Println(r)
|
||||
fmt.Println(u)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// getQueriedSqls
|
||||
func getQueriedSqls() {
|
||||
for k, v := range db.GetQueriedSqls() {
|
||||
fmt.Println(k, ":")
|
||||
fmt.Println("Sql :", v.Sql)
|
||||
fmt.Println("Args :", v.Args)
|
||||
fmt.Println("Error:", v.Error)
|
||||
fmt.Println("Func :", v.Func)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
//data := g.Map{
|
||||
// "nickname" : "john",
|
||||
//}
|
||||
//db.SetDebug(true)
|
||||
//r, err := db.Table("user").Where("id=1").Data(data).Update()
|
||||
//fmt.Println(err)
|
||||
//fmt.Println(r.RowsAffected())
|
||||
|
||||
//data2 := g.Map{
|
||||
// "adsys1" : "ss",
|
||||
//}
|
||||
//db.SetDebug(true)
|
||||
//r, err := db.Table("cd_adsys").Where("adsys0=1").Data(data2).Update()
|
||||
//fmt.Println(err)
|
||||
//fmt.Println(r.RowsAffected())
|
||||
//return
|
||||
//db.SetDebug(true)
|
||||
//r, err := db.Table("test").Where("id=1").One()
|
||||
//fmt.Println(r["datetime"])
|
||||
//fmt.Println(r["datetime"].Time().Date())
|
||||
//fmt.Println(err)
|
||||
//create()
|
||||
//create()
|
||||
//insert()
|
||||
//query()
|
||||
//replace()
|
||||
//save()
|
||||
//batchInsert()
|
||||
//update1()
|
||||
//update2()
|
||||
//update3()
|
||||
linkopSelect1()
|
||||
//linkopSelect2()
|
||||
//linkopSelect3()
|
||||
//linkopCount1()
|
||||
//linkopUpdate1()
|
||||
//linkopUpdate2()
|
||||
//linkopUpdate3()
|
||||
//linkopUpdate4()
|
||||
//
|
||||
//transaction1()
|
||||
//transaction2()
|
||||
//
|
||||
//keepPing()
|
||||
//likeQuery()
|
||||
//mapToStruct()
|
||||
//getQueriedSqls()
|
||||
}
|
||||
24
.example/database/gdb/mysql/gdb_complecated.go
Normal file
24
.example/database/gdb/mysql/gdb_complecated.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// error!
|
||||
r, err := g.DB().Table("user").Where(g.Map{
|
||||
"or": g.Map{
|
||||
"nickname": "jim",
|
||||
"create_time > ": "2019-10-01",
|
||||
},
|
||||
"and": g.Map{
|
||||
"nickname": "tom",
|
||||
"create_time > ": "2019-10-01",
|
||||
},
|
||||
}).All()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.Dump(r)
|
||||
|
||||
}
|
||||
@ -2,22 +2,26 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
// 开启调试模式,以便于记录所有执行的SQL
|
||||
//db := g.DB()
|
||||
|
||||
gdb.AddDefaultConfigNode(gdb.ConfigNode{
|
||||
LinkInfo: "root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local",
|
||||
Type: "mysql",
|
||||
Charset: "utf8",
|
||||
})
|
||||
db, _ := gdb.New()
|
||||
|
||||
db.SetDebug(true)
|
||||
|
||||
r, e := db.Table("user").Data(g.Map{
|
||||
"passport": "1",
|
||||
"password": "1",
|
||||
"nickname": "1",
|
||||
"create_time": time.Now(),
|
||||
}).Insert()
|
||||
type User struct {
|
||||
CreateTime time.Time `orm:"create_time"`
|
||||
}
|
||||
r, e := db.Table("user").Data(User{CreateTime: time.Now()}).Insert()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
db.SetDebug(true)
|
||||
//db.SetDebug(true)
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
|
||||
34
.example/database/gdb/mysql/issue364.go
Normal file
34
.example/database/gdb/mysql/issue364.go
Normal file
@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"time"
|
||||
)
|
||||
|
||||
func test1() {
|
||||
db := g.DB()
|
||||
db.SetDebug(true)
|
||||
time.Sleep(1 * time.Minute)
|
||||
r, e := db.Table("test").Where("id", 10000).Count()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
g.Dump(r)
|
||||
}
|
||||
|
||||
func test2() {
|
||||
db := g.DB()
|
||||
db.SetDebug(true)
|
||||
dao := db.Table("test").Safe()
|
||||
time.Sleep(1 * time.Minute)
|
||||
r, e := dao.Where("id", 10000).Count()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
g.Dump(r)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test1()
|
||||
test2()
|
||||
}
|
||||
@ -6,6 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gdebug.PrintStack()
|
||||
fmt.Println(gdebug.CallerPackage())
|
||||
fmt.Println(gdebug.CallerFunction())
|
||||
}
|
||||
|
||||
60
.example/frame/mvc/app/model/defaults/user.go
Normal file
60
.example/frame/mvc/app/model/defaults/user.go
Normal file
@ -0,0 +1,60 @@
|
||||
// This is auto-generated by gf cli tool. You may not really want to edit it.
|
||||
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// User is the golang structure for table user.
|
||||
type User struct {
|
||||
Id int `orm:"id,primary" json:"id"`
|
||||
Passport string `orm:"passport" json:"passport"`
|
||||
Password string `orm:"password" json:"password"`
|
||||
Nickname string `orm:"nickname,unique" json:"nickname"`
|
||||
CreateTime *gtime.Time `orm:"create_time" json:"create_time"`
|
||||
}
|
||||
|
||||
var (
|
||||
// TableUser is the table name of user.
|
||||
TableUser = "user"
|
||||
// ModelUser is the model object of user.
|
||||
ModelUser = g.DB("default").Table(TableUser).Safe()
|
||||
)
|
||||
|
||||
// Inserts does "INSERT...INTO..." statement for inserting current object into table.
|
||||
func (r *User) Insert() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Insert()
|
||||
}
|
||||
|
||||
// Replace does "REPLACE...INTO..." statement for inserting current object into table.
|
||||
// If there's already another same record in the table (it checks using primary key or unique index),
|
||||
// it deletes it and insert this one.
|
||||
func (r *User) Replace() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Replace()
|
||||
}
|
||||
|
||||
// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *User) Save() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Save()
|
||||
}
|
||||
|
||||
// Update does "UPDATE...WHERE..." statement for updating current object from table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *User) Update() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
|
||||
func (r *User) Delete() (result sql.Result, err error) {
|
||||
return ModelUser.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
|
||||
}
|
||||
@ -1,4 +1,11 @@
|
||||
viewpath = "/home/www/templates"
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
|
||||
|
||||
[redis]
|
||||
disk = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
@ -1,15 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/.example/frame/mvc/controller/demo"
|
||||
_ "github.com/gogf/gf/.example/frame/mvc/controller/stats"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/.example/frame/mvc/app/model/defaults"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//g.Server().SetDumpRouteMap(false)
|
||||
g.Server().SetPort(8199)
|
||||
g.Server().Run()
|
||||
|
||||
u := defaults.User{Id: 1, Nickname: "test"}
|
||||
fmt.Println(gdb.GetWhereConditionOfStruct(&u))
|
||||
fmt.Println(u.Replace())
|
||||
}
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
package test
|
||||
|
||||
import "github.com/gogf/gf/database/gdb"
|
||||
|
||||
var (
|
||||
// ConfigGroup is the configuration group name for this model.
|
||||
ConfigGroup = gdb.DEFAULT_GROUP_NAME
|
||||
)
|
||||
@ -1,92 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// User is the golang structure for table user.
|
||||
type User struct {
|
||||
Id int `orm:"id,primary" json:"id"`
|
||||
Passport string `orm:"passport" json:"passport"`
|
||||
Password string `orm:"password" json:"password"`
|
||||
NickName string `orm:"nickname" json:"nick_name"`
|
||||
CreateTime *gtime.Time `orm:"create_time" json:"create_time"`
|
||||
}
|
||||
|
||||
// UserModel is the model of convenient operations for table user.
|
||||
type UserModel struct {
|
||||
*gdb.Model
|
||||
TableName string
|
||||
}
|
||||
|
||||
var (
|
||||
// UserTableName is the table name of user.
|
||||
UserTableName = "user"
|
||||
)
|
||||
|
||||
// ModelUser creates and returns a new model object for table user.
|
||||
func ModelUser() *UserModel {
|
||||
return &UserModel{
|
||||
g.DB(ConfigGroup).Table(UserTableName).Safe(),
|
||||
UserTableName,
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts does "INSERT...INTO..." statement for inserting current object into table.
|
||||
func (r *User) Insert() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Insert()
|
||||
}
|
||||
|
||||
// Replace does "REPLACE...INTO..." statement for inserting current object into table.
|
||||
// If there's already another same record in the table (it checks using primary key or unique index),
|
||||
// it deletes it and insert this one.
|
||||
func (r *User) Replace() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Replace()
|
||||
}
|
||||
|
||||
// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *User) Save() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Save()
|
||||
}
|
||||
|
||||
// Update does "UPDATE...WHERE..." statement for updating current object from table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *User) Update() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
|
||||
func (r *User) Delete() (result sql.Result, err error) {
|
||||
return ModelUser().Where(gdb.GetWhereConditionOfStruct(r)).Delete()
|
||||
}
|
||||
|
||||
// Select overwrite the Select method from gdb.Model for model
|
||||
// as retuning all objects with specified structure.
|
||||
func (m *UserModel) Select() ([]*User, error) {
|
||||
array := ([]*User)(nil)
|
||||
if err := m.Scan(&array); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return array, nil
|
||||
}
|
||||
|
||||
// First does the same logistics as One method from gdb.Model for model
|
||||
// as retuning first/one object with specified structure.
|
||||
func (m *UserModel) First() (*User, error) {
|
||||
list, err := m.Select()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) > 0 {
|
||||
return list[0], nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@ -1,19 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := ghttp.NewClient()
|
||||
c.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
r, e := c.Clone().Get("https://127.0.0.1:8199")
|
||||
fmt.Println(e)
|
||||
fmt.Println(r.StatusCode)
|
||||
r, err := ghttp.Get("http://127.0.0.1:8199/11111/11122")
|
||||
fmt.Println(err)
|
||||
fmt.Println(r.Header)
|
||||
}
|
||||
|
||||
22
.example/net/ghttp/client/upload-batch/client.go
Normal file
22
.example/net/ghttp/client/upload-batch/client.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
path1 := "/Users/john/Pictures/logo1.png"
|
||||
path2 := "/Users/john/Pictures/logo2.png"
|
||||
r, e := ghttp.Post(
|
||||
"http://127.0.0.1:8199/upload",
|
||||
fmt.Sprintf(`upload-file=@file:%s&upload-file=@file:%s`, path1, path2),
|
||||
)
|
||||
if e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
fmt.Println(string(r.ReadAll()))
|
||||
r.Close()
|
||||
}
|
||||
}
|
||||
22
.example/net/ghttp/client/upload-batch/client2.go
Normal file
22
.example/net/ghttp/client/upload-batch/client2.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
path1 := "/Users/john/Pictures/logo1.png"
|
||||
path2 := "/Users/john/Pictures/logo2.png"
|
||||
r, e := ghttp.Post(
|
||||
"http://127.0.0.1:8199/upload",
|
||||
fmt.Sprintf(`upload-file[]=@file:%s&upload-file[]=@file:%s`, path1, path2),
|
||||
)
|
||||
if e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
fmt.Println(string(r.ReadAll()))
|
||||
r.Close()
|
||||
}
|
||||
}
|
||||
80
.example/net/ghttp/client/upload-batch/server.go
Normal file
80
.example/net/ghttp/client/upload-batch/server.go
Normal file
@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Upload uploads files to /tmp .
|
||||
func Upload(r *ghttp.Request) {
|
||||
saveDir := "/tmp/"
|
||||
for _, item := range r.GetMultipartFiles("upload-file") {
|
||||
file, err := item.Open()
|
||||
if err != nil {
|
||||
r.Response.Write(err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
f, err := gfile.Create(saveDir + gfile.Basename(item.Filename))
|
||||
if err != nil {
|
||||
r.Response.Write(err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(f, file); err != nil {
|
||||
r.Response.Write(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
r.Response.Write("upload successfully")
|
||||
}
|
||||
|
||||
// UploadShow shows uploading simgle file page.
|
||||
func UploadShow(r *ghttp.Request) {
|
||||
r.Response.Write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>GF Upload File Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="/upload" method="post">
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
}
|
||||
|
||||
// UploadShowBatch shows uploading multiple files page.
|
||||
func UploadShowBatch(r *ghttp.Request) {
|
||||
r.Response.Write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>GF Upload Files Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="/upload" method="post">
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/upload", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/", Upload)
|
||||
group.ALL("/show", UploadShow)
|
||||
group.ALL("/batch", UploadShowBatch)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -9,7 +9,7 @@ import (
|
||||
|
||||
func main() {
|
||||
path := "/home/john/Workspace/Go/github.com/gogf/gf/version.go"
|
||||
r, e := ghttp.Post("http://127.0.0.1:8199/upload", "name=john&age=18&upload-file=@file:"+path)
|
||||
r, e := ghttp.Post("http://127.0.0.1:8199/upload", "upload-file=@file:"+path)
|
||||
if e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
|
||||
@ -4,28 +4,41 @@ import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"io"
|
||||
)
|
||||
|
||||
// 执行文件上传处理,上传到系统临时目录 /tmp
|
||||
// Upload uploads files to /tmp .
|
||||
func Upload(r *ghttp.Request) {
|
||||
if f, h, e := r.FormFile("upload-file"); e == nil {
|
||||
saveDir := "/tmp/"
|
||||
for _, item := range r.GetMultipartFiles("upload-file") {
|
||||
file, err := item.Open()
|
||||
if err != nil {
|
||||
r.Response.Write(err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
f, err := gfile.Create(saveDir + gfile.Basename(item.Filename))
|
||||
if err != nil {
|
||||
r.Response.Write(err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
name := gfile.Basename(h.Filename)
|
||||
buffer := make([]byte, h.Size)
|
||||
f.Read(buffer)
|
||||
gfile.PutBytes("/tmp/"+name, buffer)
|
||||
r.Response.Write(name + " uploaded successly")
|
||||
} else {
|
||||
r.Response.Write(e.Error())
|
||||
|
||||
if _, err := io.Copy(f, file); err != nil {
|
||||
r.Response.Write(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
r.Response.Write("upload successfully")
|
||||
}
|
||||
|
||||
// 展示文件上传页面
|
||||
// UploadShow shows uploading simgle file page.
|
||||
func UploadShow(r *ghttp.Request) {
|
||||
r.Response.Write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>上传文件</title>
|
||||
<title>GF Upload File Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="/upload" method="post">
|
||||
@ -37,10 +50,31 @@ func UploadShow(r *ghttp.Request) {
|
||||
`)
|
||||
}
|
||||
|
||||
// UploadShowBatch shows uploading multiple files page.
|
||||
func UploadShowBatch(r *ghttp.Request) {
|
||||
r.Response.Write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>GF Upload Files Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="/upload" method="post">
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/upload", Upload)
|
||||
s.BindHandler("/upload/show", UploadShow)
|
||||
s.Group("/upload", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/", Upload)
|
||||
group.ALL("/show", UploadShow)
|
||||
group.ALL("/batch", UploadShowBatch)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -16,8 +16,8 @@ func Order(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
s.Group("/api.v1", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareCORS)
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
@ -18,8 +18,8 @@ func Order(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
s.Group("/api.v1", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareCORS)
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
@ -24,8 +24,8 @@ func Order(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
s.Group("/api.v1", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareCORS)
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
9
.example/net/ghttp/server/form/form-client.go
Normal file
9
.example/net/ghttp/server/form/form-client.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ghttp.PostContent("http://127.0.0.1:8199/", "array[]=1&array[]=2")
|
||||
}
|
||||
@ -8,7 +8,7 @@ import (
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
g.Dump(r.GetPostMap())
|
||||
g.Dump(r.GetForm("array"))
|
||||
r.Response.WriteTpl("form.html")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
@ -3,14 +3,16 @@ package main
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetIndexFolder(true)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
glog.Println(r.Header)
|
||||
r.Response.Write("hello world")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.SetPort(8999)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ func Order(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
s.Group("/api.v1", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
@ -11,8 +11,8 @@ func Order(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Hook("/*any", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
s.Group("/api.v1", func(group *ghttp.RouterGroup) {
|
||||
group.Hook("/*any", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.CORSDefault()
|
||||
})
|
||||
g.GET("/order", Order)
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
// 优先调用的HOOK
|
||||
func beforeServeHook1(r *ghttp.Request) {
|
||||
r.SetParam("name", "GoFrame")
|
||||
r.Response.Writeln("set name")
|
||||
}
|
||||
|
||||
// 随后调用的HOOK
|
||||
func beforeServeHook2(r *ghttp.Request) {
|
||||
r.SetParam("site", "https://goframe.org")
|
||||
r.Response.Writeln("set site")
|
||||
}
|
||||
|
||||
// 允许对同一个路由同一个事件注册多个回调函数,按照注册顺序进行优先级调用。
|
||||
// 为便于在路由表中对比查看优先级,这里讲HOOK回调函数单独定义为了两个函数。
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Get("name"))
|
||||
r.Response.Writeln(r.Get("site"))
|
||||
})
|
||||
s.BindHookHandler("/", ghttp.HOOK_BEFORE_SERVE, beforeServeHook1)
|
||||
s.BindHookHandler("/", ghttp.HOOK_BEFORE_SERVE, beforeServeHook2)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("来自于HTTPS的:哈喽世界!")
|
||||
})
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容!")
|
||||
})
|
||||
|
||||
7
.example/net/ghttp/server/log/config.toml
Normal file
7
.example/net/ghttp/server/log/config.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[server]
|
||||
LogPath = "/tmp/gflog/server"
|
||||
LogStdout = true
|
||||
ErrorLogEnabled = true
|
||||
ErrorLogPattern = "error.log"
|
||||
AccessLogEnabled = true
|
||||
AccessLogPattern = "access.log"
|
||||
@ -1,26 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.BindHandler("/log/handler", func(r *ghttp.Request) {
|
||||
r.Response.WriteStatus(http.StatusNotFound, "文件找不到了")
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("halo world!")
|
||||
})
|
||||
group.ALL("/log/handler", func(r *ghttp.Request) {
|
||||
r.Response.WriteStatus(http.StatusNotFound, "File Not Found!")
|
||||
})
|
||||
})
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.SetErrorLogEnabled(true)
|
||||
//s.SetLogHandler(func(r *ghttp.Request, error ...interface{}) {
|
||||
// if len(error) > 0 {
|
||||
// // 如果是错误日志
|
||||
// fmt.Println("错误产生了:", error[0])
|
||||
// }
|
||||
// // 这里是请求日志
|
||||
// fmt.Println("请求处理完成,请求地址:", r.URL.String(), "请求结果:", r.Response.Status)
|
||||
//})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -23,9 +23,9 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
g.ALL("/user/list", func(r *ghttp.Request) {
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
group.ALL("/user/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
})
|
||||
|
||||
@ -18,7 +18,7 @@ func MiddlewareAuth(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/admin", func(g *ghttp.RouterGroup) {
|
||||
s.Group("/admin", func(group *ghttp.RouterGroup) {
|
||||
g.MiddlewarePattern("/*action", func(r *ghttp.Request) {
|
||||
if action := r.GetRouterString("action"); action != "" {
|
||||
switch action {
|
||||
@ -29,10 +29,10 @@ func main() {
|
||||
}
|
||||
MiddlewareAuth(r)
|
||||
})
|
||||
g.ALL("/login", func(r *ghttp.Request) {
|
||||
group.ALL("/login", func(r *ghttp.Request) {
|
||||
r.Response.Write("login")
|
||||
})
|
||||
g.ALL("/dashboard", func(r *ghttp.Request) {
|
||||
group.ALL("/dashboard", func(r *ghttp.Request) {
|
||||
r.Response.Write("dashboard")
|
||||
})
|
||||
})
|
||||
|
||||
@ -12,9 +12,9 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
g.ALL("/user/list", func(r *ghttp.Request) {
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareCORS)
|
||||
group.ALL("/user/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
})
|
||||
|
||||
@ -31,9 +31,9 @@ func MiddlewareError(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareAuth, MiddlewareCORS, MiddlewareError)
|
||||
g.ALL("/user/list", func(r *ghttp.Request) {
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareAuth, MiddlewareCORS, MiddlewareError)
|
||||
group.ALL("/user/list", func(r *ghttp.Request) {
|
||||
panic("db error: sql is xxxxxxx")
|
||||
})
|
||||
})
|
||||
|
||||
@ -30,12 +30,12 @@ func MiddlewareLog(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareLog)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareLog)
|
||||
})
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
g.ALL("/user/list", func(r *ghttp.Request) {
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
group.ALL("/user/list", func(r *ghttp.Request) {
|
||||
panic("custom error")
|
||||
})
|
||||
})
|
||||
|
||||
@ -7,18 +7,18 @@ import (
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(func(r *ghttp.Request) {
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
r.Response.Write("start")
|
||||
r.Middleware.Next()
|
||||
r.Response.Write("end")
|
||||
})
|
||||
g.Group("/order", func(g *ghttp.RouterGroup) {
|
||||
g.Group("/order", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
})
|
||||
g.Group("/user", func(g *ghttp.RouterGroup) {
|
||||
g.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/info", func(r *ghttp.Request) {
|
||||
r.Response.Write("info")
|
||||
})
|
||||
@ -26,11 +26,11 @@ func main() {
|
||||
r.Response.Write("edit")
|
||||
})
|
||||
})
|
||||
g.Group("/hook", func(g *ghttp.RouterGroup) {
|
||||
g.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
g.Group("/hook", func(group *ghttp.RouterGroup) {
|
||||
group.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook any")
|
||||
})
|
||||
g.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
group.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook name")
|
||||
})
|
||||
})
|
||||
|
||||
36
.example/net/ghttp/server/middleware/param.go
Normal file
36
.example/net/ghttp/server/middleware/param.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
// 前置中间件1
|
||||
func MiddlewareBefore1(r *ghttp.Request) {
|
||||
r.SetParam("name", "GoFrame")
|
||||
r.Response.Writeln("set name")
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
// 前置中间件2
|
||||
func MiddlewareBefore2(r *ghttp.Request) {
|
||||
r.SetParam("site", "https://goframe.org")
|
||||
r.Response.Writeln("set site")
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareBefore1, MiddlewareBefore2)
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.Writefln(
|
||||
"%s: %s",
|
||||
r.GetParamVar("name").String(),
|
||||
r.GetParamVar("site").String(),
|
||||
)
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -6,7 +6,7 @@ import (
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.EnablePprof()
|
||||
s.EnablePProf()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("哈喽世界!")
|
||||
})
|
||||
|
||||
@ -6,23 +6,35 @@ import (
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Uid int `gvalid:"uid@min:1"`
|
||||
Name string `params:"username" gvalid:"username @required|length:6,30"`
|
||||
Pass1 string `params:"password1" gvalid:"password1@required|password3"`
|
||||
Pass2 string `params:"password2" gvalid:"password2@required|password3|same:password1#||两次密码不一致,请重新输入"`
|
||||
}
|
||||
type User struct {
|
||||
Uid int `gvalid:"uid@min:1"`
|
||||
Name string `params:"username" gvalid:"username @required|length:6,30"`
|
||||
Pass1 string `params:"password1" gvalid:"password1@required|password3"`
|
||||
Pass2 string `params:"password2" gvalid:"password2@required|password3|same:password1#||两次密码不一致,请重新输入"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/user", func(r *ghttp.Request) {
|
||||
user := new(User)
|
||||
r.GetToStruct(user)
|
||||
if err := gvalid.CheckStruct(user, nil); err != nil {
|
||||
r.Response.WriteJson(err.Maps())
|
||||
} else {
|
||||
r.Response.Write("ok")
|
||||
}
|
||||
s.Group("/", func(rgroup *ghttp.RouterGroup) {
|
||||
rgroup.ALL("/user", func(r *ghttp.Request) {
|
||||
user := new(User)
|
||||
if err := r.GetToStruct(user); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": err,
|
||||
"errcode": 1,
|
||||
})
|
||||
}
|
||||
if err := gvalid.CheckStruct(user, nil); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": err.Maps(),
|
||||
"errcode": 1,
|
||||
})
|
||||
}
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": "ok",
|
||||
"errcode": 0,
|
||||
})
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -12,8 +12,8 @@ import (
|
||||
func main() {
|
||||
gres.Dump()
|
||||
|
||||
v := g.View()
|
||||
v.SetPath("template/layout1")
|
||||
//v := g.View()
|
||||
//v.SetPath("template/layout1")
|
||||
|
||||
s := g.Server()
|
||||
s.SetIndexFolder(true)
|
||||
@ -22,8 +22,8 @@ func main() {
|
||||
fmt.Println(r.URL.Path, r.IsFileRequest())
|
||||
})
|
||||
s.BindHandler("/template", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("layout.html")
|
||||
r.Response.WriteTpl("layout1/layout.html")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.SetPort(8198)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -29,15 +29,15 @@ func MiddlewareLog(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareLog)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareLog)
|
||||
})
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
g.GET("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
})
|
||||
g.Group("/order", func(g *ghttp.RouterGroup) {
|
||||
g.Group("/order", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
@ -45,7 +45,7 @@ func main() {
|
||||
r.Response.Write("update")
|
||||
})
|
||||
})
|
||||
g.Group("/user", func(g *ghttp.RouterGroup) {
|
||||
g.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/info", func(r *ghttp.Request) {
|
||||
r.Response.Write("info")
|
||||
})
|
||||
@ -56,11 +56,11 @@ func main() {
|
||||
r.Response.Write("drop")
|
||||
})
|
||||
})
|
||||
g.Group("/hook", func(g *ghttp.RouterGroup) {
|
||||
g.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
g.Group("/hook", func(group *ghttp.RouterGroup) {
|
||||
group.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook any")
|
||||
})
|
||||
g.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
group.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook name")
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,21 +4,21 @@ import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetSessionMaxAge(2 * time.Second)
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/clear", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
g.GET("/get", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(r.Session.Map())
|
||||
})
|
||||
g.GET("/clear", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// 测试,SESSION写入
|
||||
func SessionSet(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.WriteJson("ok")
|
||||
}
|
||||
|
||||
// 测试,SESSION读取
|
||||
func SessionGet(r *ghttp.Request) {
|
||||
r.Response.WriteJson(r.Session.Map())
|
||||
}
|
||||
|
||||
// 请求处理之前将Redis中的数据读取出来并存储到SESSION对象中。
|
||||
func RedisHandlerGet(r *ghttp.Request) {
|
||||
if !r.IsFileRequest() {
|
||||
id := r.Cookie.GetSessionId()
|
||||
if id == "" {
|
||||
return
|
||||
}
|
||||
// 应用服务器一般是多个节点构成的集群,
|
||||
// 当请求中带有SESSION ID时,自动从Redis读取并恢复数据。
|
||||
value, err := g.Redis().DoVar("GET", id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !value.IsNil() {
|
||||
if err := r.Session.Restore(value.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 请求结束时将SESSION数据存储到Redis中,或者在SESSION删除时也删除Redis中的数据。
|
||||
func RedisHandlerSet(r *ghttp.Request) {
|
||||
if !r.IsFileRequest() {
|
||||
id := r.Cookie.GetSessionId()
|
||||
if id == "" {
|
||||
return
|
||||
}
|
||||
err := (error)(nil)
|
||||
value := ([]byte)(nil)
|
||||
if r.Session.Size() > 0 {
|
||||
if value, err = r.Session.Export(); err == nil {
|
||||
if len(value) == 0 {
|
||||
return
|
||||
} else if !r.Session.IsDirty() {
|
||||
// 更新过期时间
|
||||
_, err = g.Redis().Do("EXPIRE", id, r.Server.GetSessionMaxAge())
|
||||
} else {
|
||||
// 更新Redis数据
|
||||
_, err = g.Redis().Do("SETEX", id, r.Server.GetSessionMaxAge(), value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 清空SESSION后自动删除Redis数据
|
||||
_, err = g.Redis().Do("DEL", id)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/set", SessionSet)
|
||||
s.BindHandler("/get", SessionGet)
|
||||
s.BindHookHandlerByMap("/*", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: RedisHandlerGet,
|
||||
ghttp.HOOK_AFTER_SERVE: RedisHandlerSet,
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -7,7 +7,9 @@ func main() {
|
||||
s := g.Server()
|
||||
s.SetIndexFolder(true)
|
||||
s.SetServerRoot("/Users/john/Downloads")
|
||||
s.AddSearchPath("/Users/john/Documents")
|
||||
//s.AddSearchPath("/Users/john/Documents")
|
||||
s.SetErrorLogEnabled(true)
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<H1>姓名 : {{.name}}</H1>
|
||||
12
|
||||
<H1>{{.name}}: {{.score}}</H1>
|
||||
</body>
|
||||
</html>
|
||||
@ -2,25 +2,19 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type ControllerIndex struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func (c *ControllerIndex) Info() {
|
||||
c.View.Assign("title", "Go Frame 第一个网站")
|
||||
c.View.Assigns(g.Map{
|
||||
"name": "很开心1",
|
||||
"score": 100,
|
||||
})
|
||||
c.View.Display("index.html")
|
||||
}
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.BindController("/", new(ControllerIndex))
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("Hello World")
|
||||
r.Response.WriteTpl("index.tpl", g.Map{
|
||||
"title": "Test",
|
||||
"name": "John",
|
||||
"score": 100,
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ func ws(r *ghttp.Request) {
|
||||
ws, err := r.WebSocket()
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
r.Exit()
|
||||
return
|
||||
}
|
||||
for {
|
||||
msgType, msg, err := ws.ReadMessage()
|
||||
@ -26,10 +26,10 @@ func ws(r *ghttp.Request) {
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group().Bind([]ghttp.GroupItem{
|
||||
s.Group("").Bind([]ghttp.GroupItem{
|
||||
{"ALL", "/ws", ws},
|
||||
})
|
||||
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.SetServerRoot(gfile.MainPkgPath())
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -13,7 +13,7 @@ func main() {
|
||||
ws, err := r.WebSocket()
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
r.Exit()
|
||||
return
|
||||
}
|
||||
for {
|
||||
msgType, msg, err := ws.ReadMessage()
|
||||
|
||||
@ -8,11 +8,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data, err := gtcp.SendRecv("www.baidu.com:80", []byte("HEAD / HTTP/1.1\n\n"), -1)
|
||||
if len(data) > 0 {
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
dstConn, err := gtcp.NewPoolConn("www.medlinker.com:80")
|
||||
_, err = dstConn.Write([]byte("HEAD / HTTP/1.1\n\n"))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err.Error())
|
||||
}
|
||||
fmt.Println(dstConn.RecvLine())
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
# redis配置
|
||||
[[redis-cache]]
|
||||
db = 0
|
||||
|
||||
@ -8,5 +8,5 @@ import (
|
||||
|
||||
// 使用g.Config方法获取配置管理对象,并指定默认的配置文件名称
|
||||
func main() {
|
||||
fmt.Println(g.Config("config.json").Get("viewpath"))
|
||||
fmt.Println(g.Config().Get("viewpath"))
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
// 演示在找不到配置文件时的错误提示
|
||||
func main() {
|
||||
fmt.Println(g.Config("none-exist-config.toml").Get("none"))
|
||||
fmt.Println(g.Config().Get("none"))
|
||||
}
|
||||
|
||||
16
.example/os/glog/glog_config1.go
Normal file
16
.example/os/glog/glog_config1.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := glog.SetConfigWithMap(g.Map{
|
||||
"prefix": "[TEST]",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
glog.Info(1)
|
||||
}
|
||||
@ -1,24 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetSessionMaxAge(60)
|
||||
s.SetConfigWithMap(g.Map{
|
||||
"SessionMaxAge": time.Minute,
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("captcha", map[string]string{
|
||||
"key": "value",
|
||||
})
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
fmt.Println(r.Session.Get("captcha"))
|
||||
r.Response.Write(r.Session.Get("captcha"))
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
30
.example/os/gsession/storage-memory/memory.go
Normal file
30
.example/os/gsession/storage-memory/memory.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gsession"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetConfigWithMap(g.Map{
|
||||
"SessionMaxAge": time.Minute,
|
||||
"SessionStorage": gsession.NewStorageMemory(),
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
4
.example/os/gsession/storage-redis-hashtable/config.toml
Normal file
4
.example/os/gsession/storage-redis-hashtable/config.toml
Normal file
@ -0,0 +1,4 @@
|
||||
# Redis数据库配置
|
||||
[redis]
|
||||
default = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gsession"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetConfigWithMap(g.Map{
|
||||
"SessionMaxAge": time.Minute,
|
||||
"SessionStorage": gsession.NewStorageRedisHashTable(g.Redis()),
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
4
.example/os/gsession/storage-redis/config.toml
Normal file
4
.example/os/gsession/storage-redis/config.toml
Normal file
@ -0,0 +1,4 @@
|
||||
# Redis数据库配置
|
||||
[redis]
|
||||
default = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
30
.example/os/gsession/storage-redis/redis.go
Normal file
30
.example/os/gsession/storage-redis/redis.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gsession"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetConfigWithMap(g.Map{
|
||||
"SessionMaxAge": time.Minute,
|
||||
"SessionStorage": gsession.NewStorageRedis(g.Redis()),
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
21
.example/os/gview/i18n/i18n.go
Normal file
21
.example/os/gview/i18n/i18n.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
content := `{{.name}} says "a{#hello}{#world}!"`
|
||||
result1, _ := g.View().ParseContent(content, g.Map{
|
||||
"name": "john",
|
||||
"I18nLanguage": "zh-CN",
|
||||
})
|
||||
fmt.Println(result1)
|
||||
|
||||
result2, _ := g.View().ParseContent(content, g.Map{
|
||||
"name": "john",
|
||||
"I18nLanguage": "ja",
|
||||
})
|
||||
fmt.Println(result2)
|
||||
}
|
||||
@ -1,14 +1,3 @@
|
||||
# 监控服务主动拉取监控数据配置
|
||||
[active-pulling]
|
||||
# 业务类别 腾讯问诊 订单总数
|
||||
[[active-pulling.tencent-inquiry]]
|
||||
groupId = 3533761
|
||||
metricName = "OrderCount" # 监控项名称
|
||||
url = "http://ylt.medlinker.com/monitor/ordercount" # 监控数据地址
|
||||
interval = "1m" # d:日 h:小时 m:分 s:秒
|
||||
# 业务类别 腾讯问诊 超时订单总数
|
||||
[[active-pulling.tencent-inquiry]]
|
||||
groupId = 3533711
|
||||
metricName = "TimedOutOrderCount"
|
||||
url = "http://ylt.medlinker.com/monitor/timedout-ordercount"
|
||||
interval = "1m"
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
|
||||
|
||||
@ -1,12 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, _ := json.Marshal([]interface{}{1, 2, 3, 4, 5, 123.456, "a"})
|
||||
fmt.Println(gconv.String(b))
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetRequest("nickname"))
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ language: go
|
||||
go:
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.13.x"
|
||||
|
||||
branches:
|
||||
only:
|
||||
@ -11,7 +12,7 @@ branches:
|
||||
- staging
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
- GF_DEV=1 GO111MODULE=on
|
||||
|
||||
services:
|
||||
- mysql
|
||||
@ -32,6 +33,7 @@ install:
|
||||
before_script:
|
||||
- find . -name "*.go" | xargs gofmt -w
|
||||
- git diff --name-only --exit-code || exit 1
|
||||
- echo "UPDATE mysql.user SET authentication_string=PASSWORD('12345678') WHERE user='root';\nFLUSH PRIVILEGES;\n" | mysql -u root
|
||||
- psql -c 'create database travis_ci_test;' -U postgres
|
||||
|
||||
script:
|
||||
|
||||
@ -24,6 +24,11 @@
|
||||
|Hades|alipay|¥66.66
|
||||
|蔡蔡|wechat|¥666.00
|
||||
|上海金保证网络科技|bank|¥2000.00
|
||||
|[foxhack](https://github.com/foxhack)|wechat|¥20.00
|
||||
|*栈|wechat|¥5.00
|
||||
|*络|wechat|¥10.00
|
||||
|R*s|wechat|¥18.88
|
||||
|粟*e|wechat|¥50.00
|
||||
|
||||
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ require github.com/gogf/gf latest
|
||||
|
||||
# Limitation
|
||||
```
|
||||
golang version >= 1.10
|
||||
golang version >= 1.11
|
||||
```
|
||||
|
||||
# Documentation
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
# 安装
|
||||
```html
|
||||
go get -u github.com/gogf/gf
|
||||
go get -u -v github.com/gogf/gf
|
||||
```
|
||||
推荐使用 `go.mod`:
|
||||
```
|
||||
@ -33,7 +33,7 @@ require github.com/gogf/gf latest
|
||||
|
||||
# 限制
|
||||
```shell
|
||||
golang版本 >= 1.10
|
||||
golang版本 >= 1.11
|
||||
```
|
||||
|
||||
# 架构
|
||||
|
||||
178
RELEASE.2.MD
178
RELEASE.2.MD
@ -1,4 +1,180 @@
|
||||
# `v1.9.3`
|
||||
# `v1.10.0` (2019-12-05)
|
||||
|
||||
各位`gfer`久等了,较上一次发布时间过去已有两个多月了,这段时间`GF`也在不断地迭代改进,细节比较多,拟了个大概,以下是`release log`。
|
||||
|
||||
另外,`GoFrame`也参加了2019最受欢迎中国开源软件评选投票,明天就结束了,欢迎为`GF`投票啊:https://www.oschina.net/project/top_cn_2019 网页可以投一票,微信也可以投一票。
|
||||
|
||||
## 新特性
|
||||
|
||||
1. `Web Server`新特性:
|
||||
- 改进中间件及分组路由实现:https://goframe.org/net/ghttp/router/middleware
|
||||
- 增加文件配置管理特性:https://goframe.org/net/ghttp/config
|
||||
- 改进参数获取:https://goframe.org/net/ghttp/request
|
||||
- 改进文件上传:https://goframe.org/net/ghttp/client/demo/upload
|
||||
1. `Session`增加内置的多种`Storage`实现:
|
||||
- 基本介绍:https://goframe.org/os/gsession/index
|
||||
- 文件存储:https://goframe.org/os/gsession/file
|
||||
- 内存存储:https://goframe.org/os/gsession/memory
|
||||
- `Redis`存储:https://goframe.org/os/gsession/redis
|
||||
1. 增加日志组件单例对象,并优化配置管理:
|
||||
- https://goframe.org/frame/g/index
|
||||
- https://goframe.org/os/glog/config
|
||||
1. 常用的`container`容器增加`JSON`数据格式的`Marshal`/`UnMarshal`接口实现:
|
||||
- https://goframe.org/container/gmap/index
|
||||
- https://goframe.org/container/garray/index
|
||||
- https://goframe.org/container/gset/index
|
||||
- https://goframe.org/container/gvar/index
|
||||
- https://goframe.org/container/gtype/index
|
||||
- https://goframe.org/container/glist/index
|
||||
- https://goframe.org/container/gvar/index
|
||||
1. 新增`guuid`模块,用于通用的`UUID`生成:https://goframe.org/util/guuid/index
|
||||
|
||||
## 功能改进
|
||||
|
||||
### `net`
|
||||
1. `ghttp`
|
||||
- 改进请求流程处理性能;
|
||||
- `Server`增加对`Logger`日志对象的配置;
|
||||
- `Server`开放了`GetRouterMap`方法,用于获得当前服务的路由列表信息,使得开发者可以更方便地实现自定义权限管理;
|
||||
- `Server`配置管理优化;
|
||||
- `Client`客户端对象进行了大量的改进工作;
|
||||
- `Client`客户端对象增加多文件上传功能;
|
||||
- `Request`对象增加`GetError`方法,用于获取当前处理错误;
|
||||
- `Request`对象增加独立的视图对象及视图变量绑定功能,使得每个请求可以独立视图管理,也可以通过中间件切换请求对象的视图对象。默认情况下该功能关闭,视图解析时使用的是`Server`对象的视图对象;
|
||||
- 改建`Response`对象的`CORS`功能;
|
||||
- 增加`Response.WriteTplDefault`方法,用于解析并返回默认的模板内容;
|
||||
- 增加更多的单元测试用例;
|
||||
- 其他改进;
|
||||
1. `gipv4`/`gipv6`
|
||||
- 一些改进工作;
|
||||
1. `gtcp`/`gudp`
|
||||
- 一些改进工作;
|
||||
|
||||
### `database`
|
||||
1. `gdb`
|
||||
- 大量细节改进工作;
|
||||
- 去掉查询数据为空时的`sql.ErrNoRows`错误返回,保留`Struct`/`Structs`/`Scan`方法在操作数据为空的该错误返回;
|
||||
- 调试模式开启时,输出的SQL语句改进为完整的带参数的SQL,仅作参考;
|
||||
- `Where`方法增加对`gmap`数据类型支持,包括顺序性的`ListMap`/`TreeMap`等等;
|
||||
- 查询缓存方法`Cache`的缓存时间参数类型修改为`time.Duration`;
|
||||
- 修改`Record`/`Result`的数据类型转换方法名称,原有的转换方法标记为`deprecated`;
|
||||
- `Record`/`Result`查询结果类型增加`IsEmpty`方法,用于判断结果集是否为空;
|
||||
- `Record`类型增加`GMap`方法,用于将查询记录转换为`gmap`类型;
|
||||
- 增加`Option`/`OptionOmitEmpty`方法,用于输入参数过滤,包括`Data`参数及`Where`参数:https://goframe.org/database/gdb/empty
|
||||
- 增加字段排除方法`FieldsEx`:https://goframe.org/database/gdb/senior
|
||||
- 增加日志功能特性:https://goframe.org/database/gdb/senior
|
||||
- 改进数据库配置管理:https://goframe.org/database/gdb/config
|
||||
- 增加大量单元测试;
|
||||
1. `gredis`
|
||||
- 返回数据类型转换改进:https://github.com/gogf/gf/issues/415
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
|
||||
### `os`
|
||||
1. `gcache`
|
||||
- 需要注意了:缓存的有效时间参数从`interface{}`类型调整为了`time.Duration`类型,因此不再兼容之前的`int`参数类型,以保证更好的性能;
|
||||
1. `gfcache`
|
||||
- 由于`gcache`组件的缓存时间参数类型的变更,因此该组件的时间参数也变更为了`time.Duration`类型;
|
||||
1. `gcfg`
|
||||
- 增加`Available`方法,用以判断配置是否有效;
|
||||
1. `gfile`
|
||||
- 增加`Chdir`方法,用于工作目录切换;
|
||||
1. `gtime`
|
||||
- 增加`JSON`数据格式的`Marshal`/`UnMarshal`接口实现;
|
||||
|
||||
### `container`
|
||||
1. `gmap`
|
||||
- 增加`MapStrAny`方法,用于常见`map`类型的转换;
|
||||
- 增加`MapCopy`方法,用于底层`map`数据复制;
|
||||
- 增加`FilterEmpty`方法,用于`map`空值过滤;
|
||||
- 增加`Pop`/`Pops`方法,用于随机返回`map`中的数据项(并删除);
|
||||
- 增加`Replace`方法,用于给定的`map`数据覆盖底层`map`数据项;
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
1. `garray`
|
||||
- 增加`Interfaces`转换方法,返回`[]interface{}`类型;
|
||||
- 对排序数组增加`SetComparator`方法用户自定义修改比较器;
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
1. `glist`
|
||||
- 增加`NewFrom`方法,基于给定的`[]interface{}`变量创建链表;
|
||||
- 增加`Join`方法,用于将链表项使用给定字符串连接为字符串返回;
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
1. `gset`
|
||||
- 增加`AddIfNotExistFunc`/`AddIfNotExistFuncLock`方法;
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
1. `gtree`
|
||||
- 增加`Replace`方法,用于更新现有树的数据项;
|
||||
- 其他改进;
|
||||
1. `gtype`
|
||||
- 一些细节改进工作,不一一列出;
|
||||
- 完善基准测试、单元测试;
|
||||
1. `gvar`
|
||||
- 增加`Ints`/`Uints`类型转换方法;
|
||||
- 其他改进;
|
||||
|
||||
### `crypto`
|
||||
1. `gmd5`
|
||||
- 小细节改进;
|
||||
1. `gsha1`
|
||||
- 小细节改进;
|
||||
|
||||
### `text`
|
||||
1. `gstr`
|
||||
- 改进`SplitAndTrim`方法,将`SplitAndTrimSpace`标记为`deprecated`;
|
||||
- 增加`TrimStr`方法;
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
|
||||
### `debug`
|
||||
|
||||
1. `gdebug`
|
||||
- 增加`CallerFileLineShort`/`FuncPath`/`FuncName`方法;
|
||||
- 其他改进;
|
||||
|
||||
### `encoding`
|
||||
|
||||
1. `gbase64`
|
||||
- 增加`EncodeToString`/`EncodeFile`/`EncodeFileToString`/`DecodeToString`方法;
|
||||
- 完善单元测试;
|
||||
1. `gjson`
|
||||
- 完善单元测试;
|
||||
|
||||
### `frame`
|
||||
|
||||
1. `g`/`gins`
|
||||
- https://goframe.org/frame/g/index
|
||||
- 增加`CreateVar`方法;
|
||||
- 完善单元测试;
|
||||
- 其他改进;
|
||||
|
||||
### `util`
|
||||
|
||||
1. `gconv`
|
||||
- 改进优化部分类型转换方法性能;
|
||||
- 增加`Uints`/`SliceUint`类型转换方法;
|
||||
- 增加`UnsafeStrToBytes`/`UnsafeBytesToStr`高性能的类型转换方法;
|
||||
- 增加对`MapStrAny`接口方法的支持,用于常见`map`类型的转换;
|
||||
- 其他改进;
|
||||
1. `gvalid`
|
||||
- 改进对中国身份证号的识别校验功能;
|
||||
- 增加`luhn`银行卡号的校验功能;
|
||||
1. `grand`
|
||||
- 一些性能改进工作;
|
||||
|
||||
|
||||
## Bug Fix
|
||||
1. 解决`WebSocket`关闭时的`hijacked`报错问题:https://github.com/gogf/gf/issues/381
|
||||
1. 解决静态文件服务时大文件的内存占用问题;
|
||||
1. 修复前置`Nginx`后默认情况下的`Cookie`域名设置问题;
|
||||
1. 修复`gconv.Struct`在属性为`[]struct`并且输入属性参数为空时的转换失败问题:https://github.com/gogf/gf/issues/405
|
||||
1. 其他一些修复;
|
||||
|
||||
|
||||
|
||||
# `v1.9.3` (2019-09-24)
|
||||
|
||||
该版本实际为`v2.0`的大版本发布,为避免`go module`机制严格要求`v2`版本以上需要修改`import`并加上`v2`后缀,因此使用了`v1.9`版本进行发布。
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ type Array struct {
|
||||
}
|
||||
|
||||
// New creates and returns an empty array.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(safe ...bool) *Array {
|
||||
return NewArraySize(0, 0, safe...)
|
||||
@ -36,7 +36,7 @@ func NewArray(safe ...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArraySize create and returns an array with given size and cap.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArraySize(size int, cap int, safe ...bool) *Array {
|
||||
return &Array{
|
||||
@ -56,7 +56,7 @@ func NewFromCopy(array []interface{}, safe ...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArrayFrom(array []interface{}, safe ...bool) *Array {
|
||||
return &Array{
|
||||
@ -66,7 +66,7 @@ func NewArrayFrom(array []interface{}, safe ...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArrayFromCopy(array []interface{}, safe ...bool) *Array {
|
||||
newArray := make([]interface{}, len(array))
|
||||
@ -370,6 +370,11 @@ func (a *Array) Slice() []interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// Interfaces returns current array as []interface{}.
|
||||
func (a *Array) Interfaces() []interface{} {
|
||||
return a.Slice()
|
||||
}
|
||||
|
||||
// Clone returns a new array, which is a copy of current array.
|
||||
func (a *Array) Clone() (newArray *Array) {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -23,14 +23,14 @@ type IntArray struct {
|
||||
}
|
||||
|
||||
// NewIntArray creates and returns an empty array.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArray(safe ...bool) *IntArray {
|
||||
return NewIntArraySize(0, 0, safe...)
|
||||
}
|
||||
|
||||
// NewIntArraySize create and returns an array with given size and cap.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
|
||||
return &IntArray{
|
||||
@ -40,7 +40,7 @@ func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArrayFrom(array []int, safe ...bool) *IntArray {
|
||||
return &IntArray{
|
||||
@ -50,7 +50,7 @@ func NewIntArrayFrom(array []int, safe ...bool) *IntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArrayFromCopy(array []int, safe ...bool) *IntArray {
|
||||
newArray := make([]int, len(array))
|
||||
@ -376,6 +376,17 @@ func (a *IntArray) Slice() []int {
|
||||
return array
|
||||
}
|
||||
|
||||
// Interfaces returns current array as []interface{}.
|
||||
func (a *IntArray) Interfaces() []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
array := make([]interface{}, len(a.array))
|
||||
for k, v := range a.array {
|
||||
array[k] = v
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// Clone returns a new array, which is a copy of current array.
|
||||
func (a *IntArray) Clone() (newArray *IntArray) {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -25,14 +25,14 @@ type StrArray struct {
|
||||
}
|
||||
|
||||
// NewStrArray creates and returns an empty array.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrArray(safe ...bool) *StrArray {
|
||||
return NewStrArraySize(0, 0, safe...)
|
||||
}
|
||||
|
||||
// NewStrArraySize create and returns an array with given size and cap.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
|
||||
return &StrArray{
|
||||
@ -42,7 +42,7 @@ func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
|
||||
}
|
||||
|
||||
// NewStrArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrArrayFrom(array []string, safe ...bool) *StrArray {
|
||||
return &StrArray{
|
||||
@ -52,7 +52,7 @@ func NewStrArrayFrom(array []string, safe ...bool) *StrArray {
|
||||
}
|
||||
|
||||
// NewStrArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {
|
||||
newArray := make([]string, len(array))
|
||||
@ -378,6 +378,17 @@ func (a *StrArray) Slice() []string {
|
||||
return array
|
||||
}
|
||||
|
||||
// Interfaces returns current array as []interface{}.
|
||||
func (a *StrArray) Interfaces() []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
array := make([]interface{}, len(a.array))
|
||||
for k, v := range a.array {
|
||||
array[k] = v
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// Clone returns a new array, which is a copy of current array.
|
||||
func (a *StrArray) Clone() (newArray *StrArray) {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -29,7 +29,7 @@ type SortedArray struct {
|
||||
}
|
||||
|
||||
// NewSortedArray creates and returns an empty sorted array.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety, which is false in default.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety, which is false in default.
|
||||
// The parameter <comparator> used to compare values to sort in array,
|
||||
// if it returns value < 0, means v1 < v2;
|
||||
// if it returns value = 0, means v1 = v2;
|
||||
@ -39,7 +39,7 @@ func NewSortedArray(comparator func(a, b interface{}) int, safe ...bool) *Sorted
|
||||
}
|
||||
|
||||
// NewSortedArraySize create and returns an sorted array with given size and cap.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
|
||||
return &SortedArray{
|
||||
@ -51,7 +51,7 @@ func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...
|
||||
}
|
||||
|
||||
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArrayFrom(array []interface{}, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
|
||||
a := NewSortedArraySize(0, comparator, safe...)
|
||||
@ -63,7 +63,7 @@ func NewSortedArrayFrom(array []interface{}, comparator func(a, b interface{}) i
|
||||
}
|
||||
|
||||
// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArrayFromCopy(array []interface{}, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
|
||||
newArray := make([]interface{}, len(array))
|
||||
@ -342,6 +342,11 @@ func (a *SortedArray) Slice() []interface{} {
|
||||
return array
|
||||
}
|
||||
|
||||
// Interfaces returns current array as []interface{}.
|
||||
func (a *SortedArray) Interfaces() []interface{} {
|
||||
return a.Slice()
|
||||
}
|
||||
|
||||
// Contains checks whether a value exists in the array.
|
||||
func (a *SortedArray) Contains(value interface{}) bool {
|
||||
return a.Search(value) != -1
|
||||
|
||||
@ -27,14 +27,14 @@ type SortedIntArray struct {
|
||||
}
|
||||
|
||||
// NewSortedIntArray creates and returns an empty sorted array.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArray(safe ...bool) *SortedIntArray {
|
||||
return NewSortedIntArraySize(0, safe...)
|
||||
}
|
||||
|
||||
// NewSortedIntArrayComparator creates and returns an empty sorted array with specified comparator.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety which is false in default.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety which is false in default.
|
||||
func NewSortedIntArrayComparator(comparator func(a, b int) int, safe ...bool) *SortedIntArray {
|
||||
array := NewSortedIntArray(safe...)
|
||||
array.comparator = comparator
|
||||
@ -42,7 +42,7 @@ func NewSortedIntArrayComparator(comparator func(a, b int) int, safe ...bool) *S
|
||||
}
|
||||
|
||||
// NewSortedIntArraySize create and returns an sorted array with given size and cap.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
|
||||
return &SortedIntArray{
|
||||
@ -54,7 +54,7 @@ func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArrayFrom(array []int, safe ...bool) *SortedIntArray {
|
||||
a := NewSortedIntArraySize(0, safe...)
|
||||
@ -64,7 +64,7 @@ func NewSortedIntArrayFrom(array []int, safe ...bool) *SortedIntArray {
|
||||
}
|
||||
|
||||
// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArrayFromCopy(array []int, safe ...bool) *SortedIntArray {
|
||||
newArray := make([]int, len(array))
|
||||
@ -328,6 +328,17 @@ func (a *SortedIntArray) Slice() []int {
|
||||
return array
|
||||
}
|
||||
|
||||
// Interfaces returns current array as []interface{}.
|
||||
func (a *SortedIntArray) Interfaces() []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
array := make([]interface{}, len(a.array))
|
||||
for k, v := range a.array {
|
||||
array[k] = v
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// Contains checks whether a value exists in the array.
|
||||
func (a *SortedIntArray) Contains(value int) bool {
|
||||
return a.Search(value) != -1
|
||||
|
||||
@ -28,14 +28,14 @@ type SortedStrArray struct {
|
||||
}
|
||||
|
||||
// NewSortedStrArray creates and returns an empty sorted array.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStrArray(safe ...bool) *SortedStrArray {
|
||||
return NewSortedStrArraySize(0, safe...)
|
||||
}
|
||||
|
||||
// NewSortedStrArrayComparator creates and returns an empty sorted array with specified comparator.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety which is false in default.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety which is false in default.
|
||||
func NewSortedStrArrayComparator(comparator func(a, b string) int, safe ...bool) *SortedStrArray {
|
||||
array := NewSortedStrArray(safe...)
|
||||
array.comparator = comparator
|
||||
@ -43,7 +43,7 @@ func NewSortedStrArrayComparator(comparator func(a, b string) int, safe ...bool)
|
||||
}
|
||||
|
||||
// NewSortedStrArraySize create and returns an sorted array with given size and cap.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {
|
||||
return &SortedStrArray{
|
||||
@ -55,7 +55,7 @@ func NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {
|
||||
}
|
||||
|
||||
// NewSortedStrArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStrArrayFrom(array []string, safe ...bool) *SortedStrArray {
|
||||
a := NewSortedStrArraySize(0, safe...)
|
||||
@ -65,7 +65,7 @@ func NewSortedStrArrayFrom(array []string, safe ...bool) *SortedStrArray {
|
||||
}
|
||||
|
||||
// NewSortedStrArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using array in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStrArrayFromCopy(array []string, safe ...bool) *SortedStrArray {
|
||||
newArray := make([]string, len(array))
|
||||
@ -329,6 +329,17 @@ func (a *SortedStrArray) Slice() []string {
|
||||
return array
|
||||
}
|
||||
|
||||
// Interfaces returns current array as []interface{}.
|
||||
func (a *SortedStrArray) Interfaces() []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
array := make([]interface{}, len(a.array))
|
||||
for k, v := range a.array {
|
||||
array[k] = v
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// Contains checks whether a value exists in the array.
|
||||
func (a *SortedStrArray) Contains(value string) bool {
|
||||
return a.Search(value) != -1
|
||||
|
||||
@ -26,6 +26,7 @@ func Test_Array_Basic(t *testing.T) {
|
||||
array2 := garray.NewArrayFrom(expect)
|
||||
array3 := garray.NewArrayFrom([]interface{}{})
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
|
||||
@ -27,6 +27,7 @@ func Test_IntArray_Basic(t *testing.T) {
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
array2 := garray.NewIntArrayFrom(expect2)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
|
||||
@ -27,6 +27,7 @@ func Test_StrArray_Basic(t *testing.T) {
|
||||
array2 := garray.NewStrArrayFrom(expect, true)
|
||||
array3 := garray.NewStrArrayFrom([]string{})
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, "100")
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
|
||||
@ -561,6 +561,7 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
gtest.Assert(a3.Interfaces(), s1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
|
||||
@ -26,6 +26,7 @@ func TestNewSortedIntArrayFrom(t *testing.T) {
|
||||
array1 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
gtest.Assert(array1.Slice(), a1)
|
||||
gtest.Assert(array1.Interfaces(), a1)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -448,11 +448,13 @@ func TestSortedStrArray_Json(t *testing.T) {
|
||||
a2 := garray.NewSortedStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(a2.Slice(), s2)
|
||||
gtest.Assert(a2.Interfaces(), s2)
|
||||
|
||||
var a3 garray.SortedStrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
gtest.Assert(a3.Interfaces(), s1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
|
||||
@ -36,7 +36,7 @@ func New(safe ...bool) *List {
|
||||
}
|
||||
|
||||
// NewFrom creates and returns a list from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using list in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using list in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewFrom(array []interface{}, safe ...bool) *List {
|
||||
l := list.New()
|
||||
|
||||
@ -11,33 +11,33 @@ package gmap
|
||||
type Map = AnyAnyMap
|
||||
type HashMap = AnyAnyMap
|
||||
|
||||
// New returns an empty hash map.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// New creates and returns an empty hash map.
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(safe ...bool) *Map {
|
||||
return NewAnyAnyMap(safe...)
|
||||
}
|
||||
|
||||
// NewFrom returns a hash map from given map <data>.
|
||||
// NewFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using tree in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewFrom(data map[interface{}]interface{}, safe ...bool) *Map {
|
||||
return NewAnyAnyMapFrom(data, safe...)
|
||||
}
|
||||
|
||||
// NewHashMap returns an empty hash map.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// NewHashMap creates and returns an empty hash map.
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewHashMap(safe ...bool) *Map {
|
||||
return NewAnyAnyMap(safe...)
|
||||
}
|
||||
|
||||
// NewHashMapFrom returns a hash map from given map <data>.
|
||||
// NewHashMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using tree in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewHashMapFrom(data map[interface{}]interface{}, safe ...bool) *Map {
|
||||
return NewAnyAnyMapFrom(data, safe...)
|
||||
|
||||
@ -22,8 +22,8 @@ type AnyAnyMap struct {
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewAnyAnyMap returns an empty hash map.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// NewAnyAnyMap creates and returns an empty hash map.
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewAnyAnyMap(safe ...bool) *AnyAnyMap {
|
||||
return &AnyAnyMap{
|
||||
@ -32,7 +32,7 @@ func NewAnyAnyMap(safe ...bool) *AnyAnyMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewAnyAnyMapFrom returns a hash map from given map <data>.
|
||||
// NewAnyAnyMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewAnyAnyMapFrom(data map[interface{}]interface{}, safe ...bool) *AnyAnyMap {
|
||||
@ -75,7 +75,7 @@ func (m *AnyAnyMap) Map() map[interface{}]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *AnyAnyMap) MapCopy() map[interface{}]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -86,7 +86,7 @@ func (m *AnyAnyMap) MapCopy() map[interface{}]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *AnyAnyMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
@ -141,6 +141,41 @@ func (m *AnyAnyMap) Get(key interface{}) interface{} {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *AnyAnyMap) Pop() (key, value interface{}) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *AnyAnyMap) Pops(size int) map[interface{}]interface{} {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[interface{}]interface{}, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -159,12 +194,14 @@ func (m *AnyAnyMap) doSetWithLockCheck(key interface{}, value interface{}) inter
|
||||
if f, ok := value.(func() interface{}); ok {
|
||||
value = f()
|
||||
}
|
||||
m.data[key] = value
|
||||
if value != nil {
|
||||
m.data[key] = value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *AnyAnyMap) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -174,8 +211,8 @@ func (m *AnyAnyMap) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
func (m *AnyAnyMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -185,8 +222,8 @@ func (m *AnyAnyMap) GetOrSetFunc(key interface{}, f func() interface{}) interfac
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -222,7 +259,7 @@ func (m *AnyAnyMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *
|
||||
return gvar.New(m.GetOrSetFuncLock(key, f))
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *AnyAnyMap) SetIfNotExist(key interface{}, value interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -232,7 +269,7 @@ func (m *AnyAnyMap) SetIfNotExist(key interface{}, value interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *AnyAnyMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -242,7 +279,7 @@ func (m *AnyAnyMap) SetIfNotExistFunc(key interface{}, f func() interface{}) boo
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -321,10 +358,7 @@ func (m *AnyAnyMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *AnyAnyMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -334,6 +368,13 @@ func (m *AnyAnyMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *AnyAnyMap) Replace(data map[interface{}]interface{}) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *AnyAnyMap) LockFunc(f func(m map[interface{}]interface{})) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -23,7 +23,7 @@ type IntAnyMap struct {
|
||||
}
|
||||
|
||||
// NewIntAnyMap returns an empty IntAnyMap object.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntAnyMap(safe ...bool) *IntAnyMap {
|
||||
return &IntAnyMap{
|
||||
@ -32,7 +32,7 @@ func NewIntAnyMap(safe ...bool) *IntAnyMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntAnyMapFrom returns a hash map from given map <data>.
|
||||
// NewIntAnyMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewIntAnyMapFrom(data map[int]interface{}, safe ...bool) *IntAnyMap {
|
||||
@ -75,7 +75,7 @@ func (m *IntAnyMap) Map() map[int]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *IntAnyMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
@ -86,7 +86,7 @@ func (m *IntAnyMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *IntAnyMap) MapCopy() map[int]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -141,6 +141,41 @@ func (m *IntAnyMap) Get(key int) interface{} {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *IntAnyMap) Pop() (key int, value interface{}) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *IntAnyMap) Pops(size int) map[int]interface{} {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[int]interface{}, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -166,7 +201,7 @@ func (m *IntAnyMap) doSetWithLockCheck(key int, value interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *IntAnyMap) GetOrSet(key int, value interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -176,7 +211,7 @@ func (m *IntAnyMap) GetOrSet(key int, value interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist and returns this value.
|
||||
func (m *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -186,7 +221,7 @@ func (m *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist and returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -222,7 +257,7 @@ func (m *IntAnyMap) GetVarOrSetFuncLock(key int, f func() interface{}) *gvar.Var
|
||||
return gvar.New(m.GetOrSetFuncLock(key, f))
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *IntAnyMap) SetIfNotExist(key int, value interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -232,7 +267,7 @@ func (m *IntAnyMap) SetIfNotExist(key int, value interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *IntAnyMap) SetIfNotExistFunc(key int, f func() interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -242,7 +277,7 @@ func (m *IntAnyMap) SetIfNotExistFunc(key int, f func() interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -321,10 +356,7 @@ func (m *IntAnyMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *IntAnyMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -334,6 +366,13 @@ func (m *IntAnyMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *IntAnyMap) Replace(data map[int]interface{}) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *IntAnyMap) LockFunc(f func(m map[int]interface{})) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -21,7 +21,7 @@ type IntIntMap struct {
|
||||
}
|
||||
|
||||
// NewIntIntMap returns an empty IntIntMap object.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntIntMap(safe ...bool) *IntIntMap {
|
||||
return &IntIntMap{
|
||||
@ -30,7 +30,7 @@ func NewIntIntMap(safe ...bool) *IntIntMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntIntMapFrom returns a hash map from given map <data>.
|
||||
// NewIntIntMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewIntIntMapFrom(data map[int]int, safe ...bool) *IntIntMap {
|
||||
@ -73,7 +73,7 @@ func (m *IntIntMap) Map() map[int]int {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *IntIntMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
@ -84,7 +84,7 @@ func (m *IntIntMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *IntIntMap) MapCopy() map[int]int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -139,6 +139,41 @@ func (m *IntIntMap) Get(key int) int {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *IntIntMap) Pop() (key, value int) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *IntIntMap) Pops(size int) map[int]int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[int]int, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -156,7 +191,7 @@ func (m *IntIntMap) doSetWithLockCheck(key int, value int) int {
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *IntIntMap) GetOrSet(key int, value int) int {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -166,7 +201,7 @@ func (m *IntIntMap) GetOrSet(key int, value int) int {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist and returns this value.
|
||||
func (m *IntIntMap) GetOrSetFunc(key int, f func() int) int {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -176,7 +211,7 @@ func (m *IntIntMap) GetOrSetFunc(key int, f func() int) int {
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist and returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -195,7 +230,7 @@ func (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int {
|
||||
}
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *IntIntMap) SetIfNotExist(key int, value int) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -205,7 +240,7 @@ func (m *IntIntMap) SetIfNotExist(key int, value int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *IntIntMap) SetIfNotExistFunc(key int, f func() int) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -215,7 +250,7 @@ func (m *IntIntMap) SetIfNotExistFunc(key int, f func() int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -298,10 +333,7 @@ func (m *IntIntMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *IntIntMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -311,6 +343,13 @@ func (m *IntIntMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *IntIntMap) Replace(data map[int]int) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *IntIntMap) LockFunc(f func(m map[int]int)) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -21,7 +21,7 @@ type IntStrMap struct {
|
||||
}
|
||||
|
||||
// NewIntStrMap returns an empty IntStrMap object.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntStrMap(safe ...bool) *IntStrMap {
|
||||
return &IntStrMap{
|
||||
@ -30,7 +30,7 @@ func NewIntStrMap(safe ...bool) *IntStrMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntStrMapFrom returns a hash map from given map <data>.
|
||||
// NewIntStrMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap {
|
||||
@ -73,7 +73,7 @@ func (m *IntStrMap) Map() map[int]string {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *IntStrMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
@ -84,7 +84,7 @@ func (m *IntStrMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *IntStrMap) MapCopy() map[int]string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -139,6 +139,41 @@ func (m *IntStrMap) Get(key int) string {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *IntStrMap) Pop() (key int, value string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *IntStrMap) Pops(size int) map[int]string {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[int]string, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -146,17 +181,16 @@ func (m *IntStrMap) Get(key int) string {
|
||||
// It returns value with given <key>.
|
||||
func (m *IntStrMap) doSetWithLockCheck(key int, value string) string {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if v, ok := m.data[key]; ok {
|
||||
m.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
m.data[key] = value
|
||||
m.mu.Unlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *IntStrMap) GetOrSet(key int, value string) string {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -166,7 +200,7 @@ func (m *IntStrMap) GetOrSet(key int, value string) string {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist and returns this value.
|
||||
func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -176,7 +210,7 @@ func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string {
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist and returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -188,14 +222,16 @@ func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {
|
||||
return v
|
||||
}
|
||||
v = f()
|
||||
m.data[key] = v
|
||||
if v != "" {
|
||||
m.data[key] = v
|
||||
}
|
||||
return v
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *IntStrMap) SetIfNotExist(key int, value string) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -205,7 +241,7 @@ func (m *IntStrMap) SetIfNotExist(key int, value string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -215,7 +251,7 @@ func (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -298,10 +334,7 @@ func (m *IntStrMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *IntStrMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -311,6 +344,13 @@ func (m *IntStrMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *IntStrMap) Replace(data map[int]string) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *IntStrMap) LockFunc(f func(m map[int]string)) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -23,7 +23,7 @@ type StrAnyMap struct {
|
||||
}
|
||||
|
||||
// NewStrAnyMap returns an empty StrAnyMap object.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrAnyMap(safe ...bool) *StrAnyMap {
|
||||
return &StrAnyMap{
|
||||
@ -32,7 +32,7 @@ func NewStrAnyMap(safe ...bool) *StrAnyMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewStrAnyMapFrom returns a hash map from given map <data>.
|
||||
// NewStrAnyMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewStrAnyMapFrom(data map[string]interface{}, safe ...bool) *StrAnyMap {
|
||||
@ -75,12 +75,12 @@ func (m *StrAnyMap) Map() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *StrAnyMap) MapStrAny() map[string]interface{} {
|
||||
return m.Map()
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *StrAnyMap) MapCopy() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -135,6 +135,41 @@ func (m *StrAnyMap) Get(key string) interface{} {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *StrAnyMap) Pop() (key string, value interface{}) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *StrAnyMap) Pops(size int) map[string]interface{} {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[string]interface{}, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -160,7 +195,7 @@ func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -170,8 +205,8 @@ func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -181,8 +216,8 @@ func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -218,7 +253,7 @@ func (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() interface{}) *gvar.
|
||||
return gvar.New(m.GetOrSetFuncLock(key, f))
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -228,7 +263,7 @@ func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -238,7 +273,7 @@ func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -317,10 +352,7 @@ func (m *StrAnyMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *StrAnyMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -330,6 +362,13 @@ func (m *StrAnyMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *StrAnyMap) Replace(data map[string]interface{}) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *StrAnyMap) LockFunc(f func(m map[string]interface{})) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -21,7 +21,7 @@ type StrIntMap struct {
|
||||
}
|
||||
|
||||
// NewStrIntMap returns an empty StrIntMap object.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrIntMap(safe ...bool) *StrIntMap {
|
||||
return &StrIntMap{
|
||||
@ -30,7 +30,7 @@ func NewStrIntMap(safe ...bool) *StrIntMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewStrIntMapFrom returns a hash map from given map <data>.
|
||||
// NewStrIntMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewStrIntMapFrom(data map[string]int, safe ...bool) *StrIntMap {
|
||||
@ -73,7 +73,7 @@ func (m *StrIntMap) Map() map[string]int {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *StrIntMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
@ -84,7 +84,7 @@ func (m *StrIntMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *StrIntMap) MapCopy() map[string]int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -139,6 +139,41 @@ func (m *StrIntMap) Get(key string) int {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *StrIntMap) Pop() (key string, value int) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *StrIntMap) Pops(size int) map[string]int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[string]int, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -156,7 +191,7 @@ func (m *StrIntMap) doSetWithLockCheck(key string, value int) int {
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *StrIntMap) GetOrSet(key string, value int) int {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -166,8 +201,8 @@ func (m *StrIntMap) GetOrSet(key string, value int) int {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -177,8 +212,8 @@ func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int {
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -197,7 +232,7 @@ func (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int {
|
||||
}
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *StrIntMap) SetIfNotExist(key string, value int) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -207,7 +242,7 @@ func (m *StrIntMap) SetIfNotExist(key string, value int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *StrIntMap) SetIfNotExistFunc(key string, f func() int) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -217,7 +252,7 @@ func (m *StrIntMap) SetIfNotExistFunc(key string, f func() int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -300,10 +335,7 @@ func (m *StrIntMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *StrIntMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -313,6 +345,13 @@ func (m *StrIntMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *StrIntMap) Replace(data map[string]int) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *StrIntMap) LockFunc(f func(m map[string]int)) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -21,7 +21,7 @@ type StrStrMap struct {
|
||||
}
|
||||
|
||||
// NewStrStrMap returns an empty StrStrMap object.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStrStrMap(safe ...bool) *StrStrMap {
|
||||
return &StrStrMap{
|
||||
@ -30,7 +30,7 @@ func NewStrStrMap(safe ...bool) *StrStrMap {
|
||||
}
|
||||
}
|
||||
|
||||
// NewStrStrMapFrom returns a hash map from given map <data>.
|
||||
// NewStrStrMapFrom creates and returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap {
|
||||
@ -73,7 +73,7 @@ func (m *StrStrMap) Map() map[string]string {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *StrStrMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
@ -84,7 +84,7 @@ func (m *StrStrMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
// MapCopy returns a copy of the underlying data of the hash map.
|
||||
func (m *StrStrMap) MapCopy() map[string]string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
@ -139,6 +139,41 @@ func (m *StrStrMap) Get(key string) string {
|
||||
return val
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *StrStrMap) Pop() (key, value string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for key, value = range m.data {
|
||||
delete(m.data, key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *StrStrMap) Pops(size int) map[string]string {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[string]string, size)
|
||||
for k, v := range m.data {
|
||||
delete(m.data, k)
|
||||
newMap[k] = v
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -146,17 +181,16 @@ func (m *StrStrMap) Get(key string) string {
|
||||
// It returns value with given <key>.
|
||||
func (m *StrStrMap) doSetWithLockCheck(key string, value string) string {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if v, ok := m.data[key]; ok {
|
||||
m.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
m.data[key] = value
|
||||
m.mu.Unlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *StrStrMap) GetOrSet(key string, value string) string {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -166,8 +200,8 @@ func (m *StrStrMap) GetOrSet(key string, value string) string {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -177,8 +211,8 @@ func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string {
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
@ -190,14 +224,16 @@ func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string {
|
||||
return v
|
||||
}
|
||||
v = f()
|
||||
m.data[key] = v
|
||||
if v != "" {
|
||||
m.data[key] = v
|
||||
}
|
||||
return v
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *StrStrMap) SetIfNotExist(key string, value string) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -207,7 +243,7 @@ func (m *StrStrMap) SetIfNotExist(key string, value string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -217,7 +253,7 @@ func (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -300,10 +336,7 @@ func (m *StrStrMap) Size() int {
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (m *StrStrMap) IsEmpty() bool {
|
||||
m.mu.RLock()
|
||||
empty := len(m.data) == 0
|
||||
m.mu.RUnlock()
|
||||
return empty
|
||||
return m.Size() == 0
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying data map.
|
||||
@ -313,6 +346,13 @@ func (m *StrStrMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *StrStrMap) Replace(data map[string]string) {
|
||||
m.mu.Lock()
|
||||
m.data = data
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> within RWMutex.Lock.
|
||||
func (m *StrStrMap) LockFunc(f func(m map[string]string)) {
|
||||
m.mu.Lock()
|
||||
|
||||
@ -31,7 +31,7 @@ type gListMapNode struct {
|
||||
|
||||
// NewListMap returns an empty link map.
|
||||
// ListMap is backed by a hash table to store values and doubly-linked list to store ordering.
|
||||
// The parameter <safe> used to specify whether using map in concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using map in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewListMap(safe ...bool) *ListMap {
|
||||
return &ListMap{
|
||||
@ -92,7 +92,22 @@ func (m *ListMap) Clear() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the map.
|
||||
// Replace the data of the map with given <data>.
|
||||
func (m *ListMap) Replace(data map[interface{}]interface{}) {
|
||||
m.mu.Lock()
|
||||
m.data = make(map[interface{}]*glist.Element)
|
||||
m.list = glist.New()
|
||||
for key, value := range data {
|
||||
if e, ok := m.data[key]; !ok {
|
||||
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
|
||||
} else {
|
||||
e.Value = &gListMapNode{key, value}
|
||||
}
|
||||
}
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Map returns a copy of the underlying data of the map.
|
||||
func (m *ListMap) Map() map[interface{}]interface{} {
|
||||
m.mu.RLock()
|
||||
node := (*gListMapNode)(nil)
|
||||
@ -106,7 +121,7 @@ func (m *ListMap) Map() map[interface{}]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
|
||||
func (m *ListMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
node := (*gListMapNode)(nil)
|
||||
@ -189,6 +204,45 @@ func (m *ListMap) Get(key interface{}) (value interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
// Pop retrieves and deletes an item from the map.
|
||||
func (m *ListMap) Pop() (key, value interface{}) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for k, e := range m.data {
|
||||
value = e.Value.(*gListMapNode).value
|
||||
delete(m.data, k)
|
||||
m.list.Remove(e)
|
||||
return k, value
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pops retrieves and deletes <size> items from the map.
|
||||
// It returns all items if size == -1.
|
||||
func (m *ListMap) Pops(size int) map[interface{}]interface{} {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if size > len(m.data) || size == -1 {
|
||||
size = len(m.data)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
index := 0
|
||||
newMap := make(map[interface{}]interface{}, size)
|
||||
for k, e := range m.data {
|
||||
value := e.Value.(*gListMapNode).value
|
||||
delete(m.data, k)
|
||||
m.list.Remove(e)
|
||||
newMap[k] = value
|
||||
index++
|
||||
if index == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
@ -207,12 +261,14 @@ func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interfa
|
||||
if f, ok := value.(func() interface{}); ok {
|
||||
value = f()
|
||||
}
|
||||
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
|
||||
if value != nil {
|
||||
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
// or sets value with given <value> if it does not exist and then returns this value.
|
||||
func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
@ -222,8 +278,8 @@ func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
@ -233,8 +289,8 @@ func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
// or sets value with returned value of callback function <f> if it does not exist
|
||||
// and then returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the map.
|
||||
@ -270,7 +326,7 @@ func (m *ListMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gv
|
||||
return gvar.New(m.GetOrSetFuncLock(key, f))
|
||||
}
|
||||
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
|
||||
// SetIfNotExist sets <value> to the map if the <key> does not exist, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -280,7 +336,7 @@ func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
|
||||
if !m.Contains(key) {
|
||||
@ -290,7 +346,7 @@ func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, and then returns true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
@ -14,7 +14,7 @@ import (
|
||||
type TreeMap = gtree.RedBlackTree
|
||||
|
||||
// NewTreeMap instantiates a tree map with the custom comparator.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using tree in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewTreeMap(comparator func(v1, v2 interface{}) int, safe ...bool) *TreeMap {
|
||||
return gtree.NewRedBlackTree(comparator, safe...)
|
||||
@ -23,7 +23,7 @@ func NewTreeMap(comparator func(v1, v2 interface{}) int, safe ...bool) *TreeMap
|
||||
// NewTreeMapFrom instantiates a tree map with the custom comparator and <data> map.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <safe> is used to specify whether using tree in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewTreeMapFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *TreeMap {
|
||||
return gtree.NewRedBlackTreeFrom(comparator, data, safe...)
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
@ -221,3 +222,56 @@ func Test_AnyAnyMap_Json(t *testing.T) {
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
gtest.Assert(m.Size(), 2)
|
||||
|
||||
k1, v1 := m.Pop()
|
||||
gtest.AssertIN(k1, g.Slice{"k1", "k2"})
|
||||
gtest.AssertIN(v1, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 1)
|
||||
k2, v2 := m.Pop()
|
||||
gtest.AssertIN(k2, g.Slice{"k1", "k2"})
|
||||
gtest.AssertIN(v2, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.AssertNE(k1, k2)
|
||||
gtest.AssertNE(v1, v2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
"k3": "v3",
|
||||
})
|
||||
gtest.Assert(m.Size(), 3)
|
||||
|
||||
kArray := garray.New()
|
||||
vArray := garray.New()
|
||||
for k, v := range m.Pops(1) {
|
||||
gtest.AssertIN(k, g.Slice{"k1", "k2", "k3"})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 2)
|
||||
for k, v := range m.Pops(2) {
|
||||
gtest.AssertIN(k, g.Slice{"k1", "k2", "k3"})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.Assert(kArray.Unique().Len(), 3)
|
||||
gtest.Assert(vArray.Unique().Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
@ -203,3 +204,56 @@ func Test_IntAnyMap_Json(t *testing.T) {
|
||||
gtest.Assert(m.Get(2), data[2])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
gtest.Assert(m.Size(), 2)
|
||||
|
||||
k1, v1 := m.Pop()
|
||||
gtest.AssertIN(k1, g.Slice{1, 2})
|
||||
gtest.AssertIN(v1, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 1)
|
||||
k2, v2 := m.Pop()
|
||||
gtest.AssertIN(k2, g.Slice{1, 2})
|
||||
gtest.AssertIN(v2, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.AssertNE(k1, k2)
|
||||
gtest.AssertNE(v1, v2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
3: "v3",
|
||||
})
|
||||
gtest.Assert(m.Size(), 3)
|
||||
|
||||
kArray := garray.New()
|
||||
vArray := garray.New()
|
||||
for k, v := range m.Pops(1) {
|
||||
gtest.AssertIN(k, g.Slice{1, 2, 3})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 2)
|
||||
for k, v := range m.Pops(2) {
|
||||
gtest.AssertIN(k, g.Slice{1, 2, 3})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.Assert(kArray.Unique().Len(), 3)
|
||||
gtest.Assert(vArray.Unique().Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
@ -206,3 +207,56 @@ func Test_IntIntMap_Json(t *testing.T) {
|
||||
gtest.Assert(m.Get(2), data[2])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntIntMapFrom(g.MapIntInt{
|
||||
1: 11,
|
||||
2: 22,
|
||||
})
|
||||
gtest.Assert(m.Size(), 2)
|
||||
|
||||
k1, v1 := m.Pop()
|
||||
gtest.AssertIN(k1, g.Slice{1, 2})
|
||||
gtest.AssertIN(v1, g.Slice{11, 22})
|
||||
gtest.Assert(m.Size(), 1)
|
||||
k2, v2 := m.Pop()
|
||||
gtest.AssertIN(k2, g.Slice{1, 2})
|
||||
gtest.AssertIN(v2, g.Slice{11, 22})
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.AssertNE(k1, k2)
|
||||
gtest.AssertNE(v1, v2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntIntMapFrom(g.MapIntInt{
|
||||
1: 11,
|
||||
2: 22,
|
||||
3: 33,
|
||||
})
|
||||
gtest.Assert(m.Size(), 3)
|
||||
|
||||
kArray := garray.New()
|
||||
vArray := garray.New()
|
||||
for k, v := range m.Pops(1) {
|
||||
gtest.AssertIN(k, g.Slice{1, 2, 3})
|
||||
gtest.AssertIN(v, g.Slice{11, 22, 33})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 2)
|
||||
for k, v := range m.Pops(2) {
|
||||
gtest.AssertIN(k, g.Slice{1, 2, 3})
|
||||
gtest.AssertIN(v, g.Slice{11, 22, 33})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.Assert(kArray.Unique().Len(), 3)
|
||||
gtest.Assert(vArray.Unique().Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
@ -207,3 +208,56 @@ func Test_IntStrMap_Json(t *testing.T) {
|
||||
gtest.Assert(m.Get(2), data[2])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
gtest.Assert(m.Size(), 2)
|
||||
|
||||
k1, v1 := m.Pop()
|
||||
gtest.AssertIN(k1, g.Slice{1, 2})
|
||||
gtest.AssertIN(v1, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 1)
|
||||
k2, v2 := m.Pop()
|
||||
gtest.AssertIN(k2, g.Slice{1, 2})
|
||||
gtest.AssertIN(v2, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.AssertNE(k1, k2)
|
||||
gtest.AssertNE(v1, v2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
3: "v3",
|
||||
})
|
||||
gtest.Assert(m.Size(), 3)
|
||||
|
||||
kArray := garray.New()
|
||||
vArray := garray.New()
|
||||
for k, v := range m.Pops(1) {
|
||||
gtest.AssertIN(k, g.Slice{1, 2, 3})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 2)
|
||||
for k, v := range m.Pops(2) {
|
||||
gtest.AssertIN(k, g.Slice{1, 2, 3})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.Assert(kArray.Unique().Len(), 3)
|
||||
gtest.Assert(vArray.Unique().Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
|
||||
@ -177,3 +178,56 @@ func Test_ListMap_Json(t *testing.T) {
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ListMap_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewListMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
gtest.Assert(m.Size(), 2)
|
||||
|
||||
k1, v1 := m.Pop()
|
||||
gtest.AssertIN(k1, g.Slice{"k1", "k2"})
|
||||
gtest.AssertIN(v1, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 1)
|
||||
k2, v2 := m.Pop()
|
||||
gtest.AssertIN(k2, g.Slice{"k1", "k2"})
|
||||
gtest.AssertIN(v2, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.AssertNE(k1, k2)
|
||||
gtest.AssertNE(v1, v2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ListMap_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewListMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
"k3": "v3",
|
||||
})
|
||||
gtest.Assert(m.Size(), 3)
|
||||
|
||||
kArray := garray.New()
|
||||
vArray := garray.New()
|
||||
for k, v := range m.Pops(1) {
|
||||
gtest.AssertIN(k, g.Slice{"k1", "k2", "k3"})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 2)
|
||||
for k, v := range m.Pops(2) {
|
||||
gtest.AssertIN(k, g.Slice{"k1", "k2", "k3"})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.Assert(kArray.Unique().Len(), 3)
|
||||
gtest.Assert(vArray.Unique().Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
@ -215,3 +216,56 @@ func Test_StrAnyMap_Json(t *testing.T) {
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
gtest.Assert(m.Size(), 2)
|
||||
|
||||
k1, v1 := m.Pop()
|
||||
gtest.AssertIN(k1, g.Slice{"k1", "k2"})
|
||||
gtest.AssertIN(v1, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 1)
|
||||
k2, v2 := m.Pop()
|
||||
gtest.AssertIN(k2, g.Slice{"k1", "k2"})
|
||||
gtest.AssertIN(v2, g.Slice{"v1", "v2"})
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.AssertNE(k1, k2)
|
||||
gtest.AssertNE(v1, v2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
"k3": "v3",
|
||||
})
|
||||
gtest.Assert(m.Size(), 3)
|
||||
|
||||
kArray := garray.New()
|
||||
vArray := garray.New()
|
||||
for k, v := range m.Pops(1) {
|
||||
gtest.AssertIN(k, g.Slice{"k1", "k2", "k3"})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 2)
|
||||
for k, v := range m.Pops(2) {
|
||||
gtest.AssertIN(k, g.Slice{"k1", "k2", "k3"})
|
||||
gtest.AssertIN(v, g.Slice{"v1", "v2", "v3"})
|
||||
kArray.Append(k)
|
||||
vArray.Append(v)
|
||||
}
|
||||
gtest.Assert(m.Size(), 0)
|
||||
|
||||
gtest.Assert(kArray.Unique().Len(), 3)
|
||||
gtest.Assert(vArray.Unique().Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user