mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
Merge branch 'gogf:master' into master
This commit is contained in:
@ -1,12 +1,7 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
@ -47,9 +42,9 @@ func (d *MyDriver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
|
||||
|
||||
// DoQuery commits the sql string and its arguments to underlying driver
|
||||
// through given link object and returns the execution result.
|
||||
func (d *MyDriver) DoQuery(link gdb.Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
func (d *MyDriver) DoQuery(ctx context.Context, link gdb.Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
tsMilli := gtime.TimestampMilli()
|
||||
rows, err = d.DriverMysql.DoQuery(link, sql, args...)
|
||||
rows, err = d.DriverMysql.DoQuery(ctx, link, sql, args...)
|
||||
link.Exec(
|
||||
"INSERT INTO `monitor`(`sql`,`cost`,`time`,`error`) VALUES(?,?,?,?)",
|
||||
gdb.FormatSqlWithArgs(sql, args),
|
||||
@ -62,9 +57,9 @@ func (d *MyDriver) DoQuery(link gdb.Link, sql string, args ...interface{}) (rows
|
||||
|
||||
// DoExec commits the query string and its arguments to underlying driver
|
||||
// through given link object and returns the execution result.
|
||||
func (d *MyDriver) DoExec(link gdb.Link, sql string, args ...interface{}) (result sql.Result, err error) {
|
||||
func (d *MyDriver) DoExec(ctx context.Context, link gdb.Link, sql string, args ...interface{}) (result sql.Result, err error) {
|
||||
tsMilli := gtime.TimestampMilli()
|
||||
result, err = d.DriverMysql.DoExec(link, sql, args...)
|
||||
result, err = d.DriverMysql.DoExec(ctx, link, sql, args...)
|
||||
link.Exec(
|
||||
"INSERT INTO `monitor`(`sql`,`cost`,`time`,`error`) VALUES(?,?,?,?)",
|
||||
gdb.FormatSqlWithArgs(sql, args),
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
|
||||
# MySQL.
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true"
|
||||
MaxOpen = 100
|
||||
[database.logger]
|
||||
Level = "all"
|
||||
Stdout = true
|
||||
CtxKeys = ["Trace-Id"]
|
||||
[database.default]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
debug = true
|
||||
|
||||
# Redis.
|
||||
[redis]
|
||||
|
||||
24
.example/database/gdb/mysql/gdb_batch_insert.go
Normal file
24
.example/database/gdb/mysql/gdb_batch_insert.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
db.SetDebug(true)
|
||||
list := make(g.List, 0)
|
||||
for i := 0; i < 100; i++ {
|
||||
list = append(list, g.Map{
|
||||
"name": fmt.Sprintf(`name_%d`, i),
|
||||
})
|
||||
}
|
||||
r, e := db.Table("user").Data(list).Batch(2).Insert()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
if r != nil {
|
||||
fmt.Println(r.LastInsertId())
|
||||
}
|
||||
}
|
||||
14
.example/database/gdb/mysql/gdb_ctx.go
Normal file
14
.example/database/gdb/mysql/gdb_ctx.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.WithValue(context.Background(), "Trace-Id", "123456789")
|
||||
_, err := g.DB().Ctx(ctx).Query("SELECT 1")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
14
.example/database/gdb/mysql/gdb_ctx_model.go
Normal file
14
.example/database/gdb/mysql/gdb_ctx_model.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.WithValue(context.Background(), "Trace-Id", "123456789")
|
||||
_, err := g.DB().Model("user").Ctx(ctx).All()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
9
.example/database/gdb/mysql/gdb_distinct.go
Normal file
9
.example/database/gdb/mysql/gdb_distinct.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.DB().Model("user").Distinct().CountColumn("uid,name")
|
||||
}
|
||||
@ -10,9 +10,9 @@ func main() {
|
||||
//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",
|
||||
Link: "root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local",
|
||||
Type: "mysql",
|
||||
Charset: "utf8",
|
||||
})
|
||||
db, _ := gdb.New()
|
||||
|
||||
|
||||
27
.example/database/gdb/mysql/gdb_transaction.go
Normal file
27
.example/database/gdb/mysql/gdb_transaction.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
db = g.DB()
|
||||
table = "user"
|
||||
)
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.Begin(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert()
|
||||
if err = tx.Rollback(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert()
|
||||
if err = tx.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
34
.example/database/gdb/mysql/gdb_transaction_closure.go
Normal file
34
.example/database/gdb/mysql/gdb_transaction_closure.go
Normal file
@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
err error
|
||||
db = g.DB()
|
||||
table = "user"
|
||||
)
|
||||
if err = db.Transaction(func(tx *gdb.TX) error {
|
||||
// Nested transaction 1.
|
||||
if err = tx.Transaction(func(tx *gdb.TX) error {
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert()
|
||||
return err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Nested transaction 2, panic.
|
||||
if err = tx.Transaction(func(tx *gdb.TX) error {
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert()
|
||||
// Create a panic that can make this transaction rollback automatically.
|
||||
panic("error")
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
40
.example/database/gdb/mysql/gdb_transaction_savepoint.go
Normal file
40
.example/database/gdb/mysql/gdb_transaction_savepoint.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
err error
|
||||
db = g.DB()
|
||||
table = "user"
|
||||
)
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
_ = tx.Rollback()
|
||||
}
|
||||
}()
|
||||
if _, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.SavePoint("MyPoint"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err = tx.Model(table).Data(g.Map{"id": 3, "name": "green"}).Insert(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.RollbackTo("MyPoint"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
66
.example/database/gdb/mysql/gdb_with_insert.go
Normal file
66
.example/database/gdb/mysql/gdb_with_insert.go
Normal file
@ -0,0 +1,66 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gmeta"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type UserDetail struct {
|
||||
gmeta.Meta `orm:"table:user_detail"`
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type UserScore struct {
|
||||
gmeta.Meta `orm:"table:user_score"`
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
gmeta.Meta `orm:"table:user"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserDetail *UserDetail `orm:"with:uid=id"`
|
||||
UserScores []*UserScore `orm:"with:uid=id"`
|
||||
}
|
||||
|
||||
db := g.DB()
|
||||
db.Transaction(func(tx *gdb.TX) error {
|
||||
for i := 1; i <= 5; i++ {
|
||||
// User.
|
||||
user := User{
|
||||
Name: fmt.Sprintf(`name_%d`, i),
|
||||
}
|
||||
lastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Detail.
|
||||
userDetail := UserDetail{
|
||||
Uid: int(lastInsertId),
|
||||
Address: fmt.Sprintf(`address_%d`, lastInsertId),
|
||||
}
|
||||
_, err = db.Model(userDetail).Data(userDetail).OmitEmpty().Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Scores.
|
||||
for j := 1; j <= 5; j++ {
|
||||
userScore := UserScore{
|
||||
Uid: int(lastInsertId),
|
||||
Score: j,
|
||||
}
|
||||
_, err = db.Model(userScore).Data(userScore).OmitEmpty().Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
37
.example/database/gdb/mysql/gdb_with_slect.go
Normal file
37
.example/database/gdb/mysql/gdb_with_slect.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gmeta"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type UserDetail struct {
|
||||
gmeta.Meta `orm:"table:user_detail"`
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type UserScore struct {
|
||||
gmeta.Meta `orm:"table:user_score"`
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
gmeta.Meta `orm:"table:user"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserDetail *UserDetail `orm:"with:uid=id"`
|
||||
UserScores []*UserScore `orm:"with:uid=id"`
|
||||
}
|
||||
|
||||
db := g.DB()
|
||||
var user *User
|
||||
err := db.Model(user).WithAll().Where("id", 3).Scan(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.Dump(user)
|
||||
}
|
||||
@ -9,10 +9,11 @@ import (
|
||||
|
||||
// 使用原生gredis.New操作redis,但是注意需要自己调用Close方法关闭redis链接池
|
||||
func main() {
|
||||
redis := gredis.New(gredis.Config{
|
||||
config := &gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
})
|
||||
}
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.Do("SET", "k", "v")
|
||||
v, _ := redis.Do("GET", "k")
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
@ -13,6 +14,6 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(t.Translate(`hello`))
|
||||
fmt.Println(t.Translate(`{#hello}{#world}!`))
|
||||
fmt.Println(t.Translate(context.TODO(), `hello`))
|
||||
fmt.Println(t.Translate(context.TODO(), `{#hello}{#world}!`))
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
@ -13,6 +14,6 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(t.Translate(`hello`))
|
||||
fmt.Println(t.Translate(`{#hello}{#world}!`))
|
||||
fmt.Println(t.Translate(context.TODO(), `hello`))
|
||||
fmt.Println(t.Translate(context.TODO(), `{#hello}{#world}!`))
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -10,6 +12,12 @@ func main() {
|
||||
orderId = 865271654
|
||||
orderAmount = 99.8
|
||||
)
|
||||
fmt.Println(g.I18n().Tfl(`en`, `{#OrderPaid}`, orderId, orderAmount))
|
||||
fmt.Println(g.I18n().Tfl(`zh-CN`, `{#OrderPaid}`, orderId, orderAmount))
|
||||
fmt.Println(g.I18n().Tf(
|
||||
gi18n.WithLanguage(context.TODO(), `en`),
|
||||
`{#OrderPaid}`, orderId, orderAmount,
|
||||
))
|
||||
fmt.Println(g.I18n().Tf(
|
||||
gi18n.WithLanguage(context.TODO(), `zh-CN`),
|
||||
`{#OrderPaid}`, orderId, orderAmount,
|
||||
))
|
||||
}
|
||||
|
||||
@ -2,15 +2,19 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.I18n().SetPath("/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/i18n/gi18n/i18n")
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteTplContent(`{#hello}{#world}!`, g.Map{
|
||||
"I18nLanguage": r.Get("lang", "zh-CN"),
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
r.SetCtx(gi18n.WithLanguage(r.Context(), r.GetString("lang", "zh-CN")))
|
||||
r.Middleware.Next()
|
||||
})
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteTplContent(`{#hello}{#world}!`)
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
@ -1 +1,3 @@
|
||||
OrderPaid = "您已成功完成订单号 #%d 支付,支付金额¥%.2f。"
|
||||
OrderPaid = "您已成功完成订单号 #%d 支付,支付金额¥%.2f。"
|
||||
hello = "你好"
|
||||
world = "世界"
|
||||
64
.example/net/ghttp/client/middleware/client.go
Normal file
64
.example/net/ghttp/client/middleware/client.go
Normal file
@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/crypto/gmd5"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/guid"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
appId = "123"
|
||||
appSecret = "456"
|
||||
)
|
||||
|
||||
// 注入统一的接口签名参数
|
||||
func injectSignature(jsonContent []byte) []byte {
|
||||
var m map[string]interface{}
|
||||
_ = json.Unmarshal(jsonContent, &m)
|
||||
if len(m) > 0 {
|
||||
m["appid"] = appId
|
||||
m["nonce"] = guid.S()
|
||||
m["timestamp"] = gtime.Timestamp()
|
||||
var (
|
||||
keyArray = garray.NewSortedStrArrayFrom(gutil.Keys(m))
|
||||
sigContent string
|
||||
)
|
||||
keyArray.Iterator(func(k int, v string) bool {
|
||||
sigContent += v
|
||||
sigContent += gconv.String(m[v])
|
||||
return true
|
||||
})
|
||||
m["signature"] = gmd5.MustEncryptString(gmd5.MustEncryptString(sigContent) + appSecret)
|
||||
jsonContent, _ = json.Marshal(m)
|
||||
}
|
||||
return jsonContent
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := g.Client()
|
||||
c.Use(func(c *ghttp.Client, r *http.Request) (resp *ghttp.ClientResponse, err error) {
|
||||
bodyBytes, _ := ioutil.ReadAll(r.Body)
|
||||
if len(bodyBytes) > 0 {
|
||||
// 注入签名相关参数,修改Request原有的提交参数
|
||||
bodyBytes = injectSignature(bodyBytes)
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
r.ContentLength = int64(len(bodyBytes))
|
||||
}
|
||||
return c.Next(r)
|
||||
})
|
||||
content := c.ContentJson().PostContent("http://127.0.0.1:8199/", g.Map{
|
||||
"name": "goframe",
|
||||
"site": "https://goframe.org",
|
||||
})
|
||||
fmt.Println(content)
|
||||
}
|
||||
17
.example/net/ghttp/client/middleware/server.go
Normal file
17
.example/net/ghttp/client/middleware/server.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetMap())
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
18
.example/net/ghttp/server/redirect/redirect_to.go
Normal file
18
.example/net/ghttp/server/redirect/redirect_to.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.RedirectTo("/login")
|
||||
})
|
||||
s.BindHandler("/login", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("Login First")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -25,7 +25,7 @@ func main() {
|
||||
//fmt.Println(r.GetBody())
|
||||
if err := r.Parse(&req); err != nil {
|
||||
// Validation error.
|
||||
if v, ok := err.(*gvalid.Error); ok {
|
||||
if v, ok := err.(gvalid.Error); ok {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: v.FirstString(),
|
||||
|
||||
@ -18,13 +18,13 @@ func main() {
|
||||
s.Group("/", func(rgroup *ghttp.RouterGroup) {
|
||||
rgroup.ALL("/user", func(r *ghttp.Request) {
|
||||
user := new(User)
|
||||
if err := r.GetToStruct(user); err != nil {
|
||||
if err := r.GetStruct(user); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": err,
|
||||
"errcode": 1,
|
||||
})
|
||||
}
|
||||
if err := gvalid.CheckStruct(user, nil); err != nil {
|
||||
if err := gvalid.CheckStruct(r.Context(), user, nil); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": err.Maps(),
|
||||
"errcode": 1,
|
||||
|
||||
@ -24,7 +24,7 @@ func main() {
|
||||
var req *RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
// Validation error.
|
||||
if v, ok := err.(*gvalid.Error); ok {
|
||||
if v, ok := err.(gvalid.Error); ok {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: v.FirstString(),
|
||||
20
.example/net/ghttp/server/router/duplicated/duplicated.go
Normal file
20
.example/net/ghttp/server/router/duplicated/duplicated.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/test", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(1)
|
||||
})
|
||||
group.ALL("/test", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(2)
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
15
.example/net/ghttp/server/servefile/servefile.go
Normal file
15
.example/net/ghttp/server/servefile/servefile.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.ServeFile("test.txt")
|
||||
})
|
||||
s.SetPort(8999)
|
||||
s.Run()
|
||||
}
|
||||
15
.example/net/ghttp/server/servefile/servefiledownload.go
Normal file
15
.example/net/ghttp/server/servefile/servefiledownload.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.ServeFileDownload("test.txt")
|
||||
})
|
||||
s.SetPort(8999)
|
||||
s.Run()
|
||||
}
|
||||
1
.example/net/ghttp/server/servefile/test.txt
Normal file
1
.example/net/ghttp/server/servefile/test.txt
Normal file
@ -0,0 +1 @@
|
||||
test
|
||||
36
.example/net/ghttp/server/session/redis/redis_bigint.go
Normal file
36
.example/net/ghttp/server/session/redis/redis_bigint.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gsession"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
s := g.Server()
|
||||
s.SetSessionStorage(gsession.NewStorageRedis(g.Redis()))
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/set", func(r *ghttp.Request) {
|
||||
user := &User{
|
||||
Id: 1265476890672672808,
|
||||
Name: "john",
|
||||
}
|
||||
if err := r.Session.Set("user", user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
group.GET("/get", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(r.Session.Get("user"))
|
||||
})
|
||||
group.GET("/clear", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
|
||||
@ -16,7 +16,7 @@ func main() {
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if err := conn.Send([]byte("GET / HTTP/1.1\n\n")); err != nil {
|
||||
if err := conn.Send([]byte("GET / HTTP/1.1\r\n\r\n")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -30,13 +30,14 @@ func main() {
|
||||
array := bytes.Split(data, []byte(": "))
|
||||
// 获得页面内容长度
|
||||
if contentLength == 0 && len(array) == 2 && bytes.EqualFold([]byte("Content-Length"), array[0]) {
|
||||
contentLength = gconv.Int(array[1])
|
||||
// http 以\r\n换行,需要把\r也去掉
|
||||
contentLength = gconv.Int(string(array[1][:len(array[1])-1]))
|
||||
}
|
||||
header = append(header, data...)
|
||||
header = append(header, '\n')
|
||||
}
|
||||
// header读取完毕,读取文本内容
|
||||
if contentLength > 0 && len(data) == 0 {
|
||||
// header读取完毕,读取文本内容, 1为\r
|
||||
if contentLength > 0 && len(data) == 1 {
|
||||
content, _ = conn.Recv(contentLength)
|
||||
break
|
||||
}
|
||||
|
||||
28
.example/os/gcache/getorset_func_lock.go
Normal file
28
.example/os/gcache/getorset_func_lock.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/os/gctx"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ch = make(chan struct{}, 0)
|
||||
ctx = gctx.New()
|
||||
key = `key`
|
||||
value = `value`
|
||||
)
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(index int) {
|
||||
<-ch
|
||||
_, _ = gcache.Ctx(ctx).GetOrSetFuncLock(key, func() (interface{}, error) {
|
||||
fmt.Println(index, "entered")
|
||||
return value, nil
|
||||
}, 0)
|
||||
}(i)
|
||||
}
|
||||
close(ch)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
19
.example/os/gcache/note_interface_key.go
Normal file
19
.example/os/gcache/note_interface_key.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
key1 int32 = 1
|
||||
key2 float64 = 1
|
||||
value = `value`
|
||||
)
|
||||
_ = gcache.Ctx(ctx).Set(key1, value, 0)
|
||||
fmt.Println(gcache.Ctx(ctx).Get(key1))
|
||||
fmt.Println(gcache.Ctx(ctx).Get(key2))
|
||||
}
|
||||
29
.example/os/gcache/note_interface_value.go
Normal file
29
.example/os/gcache/note_interface_value.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
Site string
|
||||
}
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
user *User
|
||||
key = `UserKey`
|
||||
value = &User{
|
||||
Id: 1,
|
||||
Name: "GoFrame",
|
||||
Site: "https://goframe.org",
|
||||
}
|
||||
)
|
||||
_ = gcache.Ctx(ctx).Set(key, value, 0)
|
||||
v, _ := gcache.Ctx(ctx).GetVar(key)
|
||||
_ = v.Scan(&user)
|
||||
fmt.Printf(`%#v`, user)
|
||||
}
|
||||
14
.example/os/glog/glog_CtxKeys.go
Normal file
14
.example/os/glog/glog_CtxKeys.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Log().SetCtxKeys("TraceId", "SpanId", "Test")
|
||||
ctx := context.WithValue(context.Background(), "TraceId", "1234567890")
|
||||
ctx = context.WithValue(ctx, "SpanId", "abcdefg")
|
||||
|
||||
g.Log().Ctx(ctx).Print(1, 2, 3)
|
||||
}
|
||||
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := glog.SetConfigWithMap(g.Map{
|
||||
err := g.Log().SetConfigWithMap(g.Map{
|
||||
"prefix": "[TEST]",
|
||||
})
|
||||
if err != nil {
|
||||
@ -1,14 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for i := 0; i < 10; i++ {
|
||||
glog.Async().Print("async log", i)
|
||||
g.Log().Async().Print("async log", i)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
@ -1,15 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.SetAsync(true)
|
||||
g.Log().SetAsync(true)
|
||||
for i := 0; i < 10; i++ {
|
||||
glog.Async().Print("async log", i)
|
||||
g.Log().Print("async log", i)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
@ -3,13 +3,12 @@ package main
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
path := "/tmp/glog-cat"
|
||||
glog.SetPath(path)
|
||||
glog.Stdout(false).Cat("cat1").Cat("cat2").Println("test")
|
||||
g.Log().SetPath(path)
|
||||
g.Log().Stdout(false).Cat("cat1").Cat("cat2").Println("test")
|
||||
list, err := gfile.ScanDir(path, "*", true)
|
||||
g.Dump(err)
|
||||
g.Dump(list)
|
||||
|
||||
15
.example/os/glog/glog_color.go
Normal file
15
.example/os/glog/glog_color.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Log().Print("Print")
|
||||
g.Log().Debug("Debug")
|
||||
g.Log().Info("Info")
|
||||
g.Log().Notice("Notice")
|
||||
g.Log().Warning("Warning")
|
||||
g.Log().Error("Error")
|
||||
g.Log().Critical("Critical")
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.SetCtxKeys("Trace-Id", "Span-Id", "Test")
|
||||
ctx := context.WithValue(context.Background(), "Trace-Id", "1234567890")
|
||||
ctx = context.WithValue(ctx, "Span-Id", "abcdefg")
|
||||
|
||||
glog.Ctx(ctx).Print(1, 2, 3)
|
||||
}
|
||||
@ -1,19 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/os/gtimer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gtimer.SetTimeout(3*time.Second, func() {
|
||||
glog.SetDebug(false)
|
||||
g.Log().SetDebug(false)
|
||||
})
|
||||
for {
|
||||
glog.Debug(gtime.Datetime())
|
||||
g.Log().Debug(gtime.Datetime())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,24 +3,25 @@ package main
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
// 设置日志等级
|
||||
func main() {
|
||||
l := glog.New()
|
||||
path := "/tmp/glog"
|
||||
l.SetPath(path)
|
||||
l.SetStdoutPrint(false)
|
||||
g.Log().SetPath(path)
|
||||
g.Log().SetStdoutPrint(false)
|
||||
|
||||
// 使用默认文件名称格式
|
||||
l.Println("标准文件名称格式,使用当前时间时期")
|
||||
g.Log().Println("标准文件名称格式,使用当前时间时期")
|
||||
|
||||
// 通过SetFile设置文件名称格式
|
||||
l.SetFile("stdout.log")
|
||||
l.Println("设置日志输出文件名称格式为同一个文件")
|
||||
g.Log().SetFile("stdout.log")
|
||||
g.Log().Println("设置日志输出文件名称格式为同一个文件")
|
||||
|
||||
// 链式操作设置文件名称格式
|
||||
l.File("stderr.log").Println("支持链式操作")
|
||||
l.File("error-{Ymd}.log").Println("文件名称支持带gtime日期格式")
|
||||
l.File("access-{Ymd}.log").Println("文件名称支持带gtime日期格式")
|
||||
g.Log().File("stderr.log").Println("支持链式操作")
|
||||
g.Log().File("error-{Ymd}.log").Println("文件名称支持带gtime日期格式")
|
||||
g.Log().File("access-{Ymd}.log").Println("文件名称支持带gtime日期格式")
|
||||
|
||||
list, err := gfile.ScanDir(path, "*")
|
||||
g.Dump(err)
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := glog.New()
|
||||
l.SetFlags(glog.F_TIME_TIME | glog.F_FILE_SHORT)
|
||||
l.Println("time and short line number")
|
||||
l.SetFlags(glog.F_TIME_MILLI | glog.F_FILE_LONG)
|
||||
l.Println("time with millisecond and long line number")
|
||||
l.SetFlags(glog.F_TIME_STD | glog.F_FILE_LONG)
|
||||
l.Println("standard time format and long line number")
|
||||
g.Log().SetFlags(glog.F_TIME_TIME | glog.F_FILE_SHORT)
|
||||
g.Log().Println("time and short line number")
|
||||
g.Log().SetFlags(glog.F_TIME_MILLI | glog.F_FILE_LONG)
|
||||
g.Log().Println("time with millisecond and long line number")
|
||||
g.Log().SetFlags(glog.F_TIME_STD | glog.F_FILE_LONG)
|
||||
g.Log().Println("standard time format and long line number")
|
||||
}
|
||||
|
||||
@ -2,9 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func MakeError() error {
|
||||
@ -18,8 +18,8 @@ func MakeGError() error {
|
||||
func TestGError() {
|
||||
err1 := MakeError()
|
||||
err2 := MakeGError()
|
||||
glog.Error(err1)
|
||||
glog.Error(err2)
|
||||
g.Log().Error(err1)
|
||||
g.Log().Error(err2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@ -2,15 +2,14 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.Debug(g.Map{"uid": 100, "name": "john"})
|
||||
g.Log().Debug(g.Map{"uid": 100, "name": "john"})
|
||||
|
||||
type User struct {
|
||||
Uid int `json:"uid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
glog.Debug(User{100, "john"})
|
||||
g.Log().Debug(User{100, "john"})
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
// 设置日志等级,过滤掉Info日志信息
|
||||
func main() {
|
||||
l := glog.New()
|
||||
l.Info("info1")
|
||||
l.SetLevel(glog.LEVEL_ALL ^ glog.LEVEL_INFO)
|
||||
l.Info("info2")
|
||||
g.Log().Info("info1")
|
||||
g.Log().SetLevel(glog.LEVEL_ALL ^ glog.LEVEL_INFO)
|
||||
g.Log().Info("info2")
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := glog.New()
|
||||
l.SetLevelPrefix(glog.LEVEL_DEBU, "debug")
|
||||
l.Debug("test")
|
||||
g.Log().SetLevelPrefix(glog.LEVEL_DEBU, "debug")
|
||||
g.Log().Debug("test")
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.Line().Debug("this is the short file name with its line number")
|
||||
glog.Line(true).Debug("lone file name with line number")
|
||||
g.Log().Line().Debug("this is the short file name with its line number")
|
||||
g.Log().Line(true).Debug("lone file name with line number")
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func PrintLog(content string) {
|
||||
glog.Skip(0).Line().Println("line number with skip:", content)
|
||||
glog.Line(true).Println("line number without skip:", content)
|
||||
g.Log().Skip(0).Line().Println("line number with skip:", content)
|
||||
g.Log().Line(true).Println("line number without skip:", content)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@ -3,14 +3,13 @@ package main
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
// 设置日志输出路径
|
||||
func main() {
|
||||
path := "/tmp/glog"
|
||||
glog.SetPath(path)
|
||||
glog.Println("日志内容")
|
||||
g.Log().SetPath(path)
|
||||
g.Log().Println("日志内容")
|
||||
list, err := gfile.ScanDir(path, "*")
|
||||
g.Dump(err)
|
||||
g.Dump(list)
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// 测试删除日志文件是否会重建日志文件
|
||||
func main() {
|
||||
path := "/Users/john/Temp/test"
|
||||
glog.SetPath(path)
|
||||
g.Log().SetPath(path)
|
||||
for {
|
||||
glog.Println(gtime.Now().String())
|
||||
g.Log().Println(gtime.Now().String())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := glog.New()
|
||||
l.SetPrefix("[API]")
|
||||
l.Println("hello world")
|
||||
l.Error("error occurred")
|
||||
g.Log().SetPrefix("[API]")
|
||||
g.Log().Println("hello world")
|
||||
g.Log().Error("error occurred")
|
||||
}
|
||||
|
||||
@ -2,15 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Log().PrintStack()
|
||||
|
||||
glog.PrintStack()
|
||||
glog.New().PrintStack()
|
||||
|
||||
fmt.Println(glog.GetStack())
|
||||
fmt.Println(glog.New().GetStack())
|
||||
fmt.Println(g.Log().GetStack())
|
||||
}
|
||||
|
||||
@ -1,22 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
wg := sync.WaitGroup{}
|
||||
c := make(chan struct{})
|
||||
var (
|
||||
wg = sync.WaitGroup{}
|
||||
ch = make(chan struct{})
|
||||
)
|
||||
wg.Add(3000)
|
||||
for i := 0; i < 3000; i++ {
|
||||
go func() {
|
||||
<-c
|
||||
glog.Println("abcdefghijklmnopqrstuvwxyz1234567890")
|
||||
<-ch
|
||||
g.Log().Println("abcdefghijklmnopqrstuvwxyz1234567890")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
close(c)
|
||||
close(ch)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
@ -16,7 +16,7 @@ func (w *MyWriter) Write(p []byte) (n int, err error) {
|
||||
s := string(p)
|
||||
if gregex.IsMatchString(`\[(PANI|FATA)\]`, s) {
|
||||
fmt.Println("SERIOUS ISSUE OCCURRED!! I'd better tell monitor in first time!")
|
||||
ghttp.PostContent("http://monitor.mydomain.com", s)
|
||||
g.Client().PostContent("http://monitor.mydomain.com", s)
|
||||
}
|
||||
return w.logger.Write(p)
|
||||
}
|
||||
|
||||
31
.example/os/glog/handler/glog_handler_greylog.go
Normal file
31
.example/os/glog/handler/glog_handler_greylog.go
Normal file
@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
//import (
|
||||
// "context"
|
||||
// "github.com/gogf/gf/frame/g"
|
||||
// "github.com/gogf/gf/os/glog"
|
||||
// "github.com/robertkowalski/graylog-golang"
|
||||
//)
|
||||
//
|
||||
//var greyLogClient = gelf.New(gelf.Config{
|
||||
// GraylogPort: 80,
|
||||
// GraylogHostname: "graylog-host.com",
|
||||
// Connection: "wan",
|
||||
// MaxChunkSizeWan: 42,
|
||||
// MaxChunkSizeLan: 1337,
|
||||
//})
|
||||
//
|
||||
//// LoggingGreyLogHandler is an example handler for logging content to remote GreyLog service.
|
||||
//var LoggingGreyLogHandler glog.Handler = func(ctx context.Context, in *glog.HandlerInput) {
|
||||
// in.Next()
|
||||
// greyLogClient.Log(in.Buffer.String())
|
||||
//}
|
||||
//
|
||||
//func main() {
|
||||
// g.Log().SetHandlers(LoggingGreyLogHandler)
|
||||
//
|
||||
// g.Log().Debug("Debugging...")
|
||||
// g.Log().Warning("It is warning info")
|
||||
// g.Log().Error("Error occurs, please have a check")
|
||||
// glog.Println("test log")
|
||||
//}
|
||||
42
.example/os/glog/handler/glog_handler_json.go
Normal file
42
.example/os/glog/handler/glog_handler_json.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"os"
|
||||
)
|
||||
|
||||
// JsonOutputsForLogger is for JSON marshaling in sequence.
|
||||
type JsonOutputsForLogger struct {
|
||||
Time string `json:"time"`
|
||||
Level string `json:"level"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// LoggingJsonHandler is an example handler for logging JSON format content.
|
||||
var LoggingJsonHandler glog.Handler = func(ctx context.Context, in *glog.HandlerInput) {
|
||||
jsonForLogger := JsonOutputsForLogger{
|
||||
Time: in.TimeFormat,
|
||||
Level: in.LevelFormat,
|
||||
Content: gstr.Trim(in.String()),
|
||||
}
|
||||
jsonBytes, err := json.Marshal(jsonForLogger)
|
||||
if err != nil {
|
||||
_, _ = os.Stderr.WriteString(err.Error())
|
||||
return
|
||||
}
|
||||
in.Buffer.Write(jsonBytes)
|
||||
in.Buffer.WriteString("\n")
|
||||
in.Next()
|
||||
}
|
||||
|
||||
func main() {
|
||||
g.Log().SetHandlers(LoggingJsonHandler)
|
||||
|
||||
g.Log().Debug("Debugging...")
|
||||
g.Log().Warning("It is warning info")
|
||||
g.Log().Error("Error occurs, please have a check")
|
||||
}
|
||||
@ -10,8 +10,10 @@ import (
|
||||
|
||||
// 内存锁基本使用
|
||||
func main() {
|
||||
key := "lock"
|
||||
wg := sync.WaitGroup{}
|
||||
var (
|
||||
key = "lock"
|
||||
wg = sync.WaitGroup{}
|
||||
)
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
@ -11,12 +11,13 @@ import (
|
||||
|
||||
// 测试Locker是否会产生死锁
|
||||
func main() {
|
||||
l := gmlock.New()
|
||||
wg := sync.WaitGroup{}
|
||||
key := "test"
|
||||
event := make(chan int)
|
||||
number := 100000
|
||||
|
||||
var (
|
||||
l = gmlock.New()
|
||||
wg = sync.WaitGroup{}
|
||||
key = "test"
|
||||
event = make(chan int)
|
||||
number = 100000
|
||||
)
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
@ -1,23 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/os/gmlock"
|
||||
)
|
||||
|
||||
// 内存锁 - 给定过期时间
|
||||
func main() {
|
||||
key := "lock"
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
gmlock.Lock(key, 1000)
|
||||
glog.Println(i)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/gmlock"
|
||||
)
|
||||
|
||||
// 测试是否会产生死锁
|
||||
func main() {
|
||||
mu := gmlock.NewMutex()
|
||||
wg := sync.WaitGroup{}
|
||||
event := make(chan int)
|
||||
number := 100000
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-event
|
||||
mu.Lock()
|
||||
//fmt.Println("get lock")
|
||||
mu.Unlock()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-event
|
||||
mu.RLock()
|
||||
//fmt.Println("get rlock")
|
||||
mu.RUnlock()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-event
|
||||
if mu.TryLock() {
|
||||
//fmt.Println("get lock")
|
||||
mu.Unlock()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-event
|
||||
if mu.TryRLock() {
|
||||
//fmt.Println("get rlock")
|
||||
mu.RUnlock()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-event
|
||||
if mu.TryLock() {
|
||||
// 模拟业务逻辑的随机处理间隔
|
||||
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
||||
mu.Unlock()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-event
|
||||
if mu.TryRLock() {
|
||||
// 模拟业务逻辑的随机处理间隔
|
||||
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
||||
mu.RUnlock()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
// 使用chan作为事件发送测试指令,让所有的goroutine同时执行
|
||||
close(event)
|
||||
wg.Wait()
|
||||
|
||||
fmt.Println("done!")
|
||||
}
|
||||
54
.example/os/gproc/signal/signal_handler.go
Normal file
54
.example/os/gproc/signal/signal_handler.go
Normal file
@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func signalHandlerForMQ() {
|
||||
var (
|
||||
sig os.Signal
|
||||
receivedChan = make(chan os.Signal)
|
||||
)
|
||||
signal.Notify(
|
||||
receivedChan,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
syscall.SIGKILL,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGABRT,
|
||||
)
|
||||
for {
|
||||
sig = <-receivedChan
|
||||
fmt.Println("MQ is shutting down due to signal:", sig.String())
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("MQ is shut down smoothly")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Process start, pid:", os.Getpid())
|
||||
go signalHandlerForMQ()
|
||||
|
||||
var (
|
||||
sig os.Signal
|
||||
receivedChan = make(chan os.Signal)
|
||||
)
|
||||
signal.Notify(
|
||||
receivedChan,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
syscall.SIGKILL,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGABRT,
|
||||
)
|
||||
for {
|
||||
sig = <-receivedChan
|
||||
fmt.Println("MainProcess is shutting down due to signal:", sig.String())
|
||||
return
|
||||
}
|
||||
}
|
||||
27
.example/os/gproc/signal/signal_handler_gproc.go
Normal file
27
.example/os/gproc/signal/signal_handler_gproc.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func signalHandlerForMQ(sig os.Signal) {
|
||||
fmt.Println("MQ is shutting down due to signal:", sig.String())
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("MQ is shut down smoothly")
|
||||
}
|
||||
|
||||
func signalHandlerForMain(sig os.Signal) {
|
||||
fmt.Println("MainProcess is shutting down due to signal:", sig.String())
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Process start, pid:", os.Getpid())
|
||||
gproc.AddSigHandlerShutdown(
|
||||
signalHandlerForMQ,
|
||||
signalHandlerForMain,
|
||||
)
|
||||
gproc.Listen()
|
||||
}
|
||||
14
.example/util/gvalid/config.toml
Normal file
14
.example/util/gvalid/config.toml
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
|
||||
# MySQL.
|
||||
[database]
|
||||
[database.default]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
debug = true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,31 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//rule := "length:6,16"
|
||||
//if m := gvalid.Check("123456", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "123456", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
//}
|
||||
//if m := gvalid.Check("12345", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "12345", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
// // map[length:字段长度为6到16个字符]
|
||||
//}
|
||||
|
||||
//rule := "integer|between:6,16"
|
||||
//msgs := "请输入一个整数|参数大小不对啊老铁"
|
||||
//fmt.Println(gvalid.Check("5.66", rule, msgs))
|
||||
//fmt.Println(gvalid.Check(context.TODO(), "5.66", rule, msgs))
|
||||
//// map[integer:请输入一个整数 between:参数大小不对啊老铁]
|
||||
|
||||
//// 参数长度至少为6个数字或者6个字母,但是总长度不能超过16个字符
|
||||
//rule := `regex:\d{6,}|\D{6,}|max-length:16`
|
||||
//if m := gvalid.Check("123456", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "123456", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
//}
|
||||
//if m := gvalid.Check("abcde6", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "abcde6", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
// // map[regex:字段值不合法]
|
||||
//}
|
||||
@ -40,18 +41,20 @@ func main() {
|
||||
// "password" : "required|length:6,16|same:password2",
|
||||
// "password2" : "required|length:6,16",
|
||||
//}
|
||||
//fmt.Println(gvalid.CheckMap(params, rules))
|
||||
//fmt.Println(gvalid.CheckMap(context.TODO(), params, rules))
|
||||
//// map[passport:map[length:字段长度为6到16个字符] password:map[same:字段值不合法]]
|
||||
|
||||
params := map[string]interface{}{
|
||||
"passport": "john",
|
||||
"password": "123456",
|
||||
"password2": "1234567",
|
||||
"name": "gf",
|
||||
}
|
||||
rules := map[string]string{
|
||||
"passport": "required|length:6,16",
|
||||
"password": "required|length:6,16|same:password2",
|
||||
"password2": "required|length:6,16",
|
||||
"name": "size:5",
|
||||
}
|
||||
msgs := map[string]interface{}{
|
||||
"passport": "账号不能为空|账号长度应当在:min到:max之间",
|
||||
@ -59,8 +62,9 @@ func main() {
|
||||
"required": "密码不能为空",
|
||||
"same": "两次密码输入不相等",
|
||||
},
|
||||
"name": "名字长度必须为:size",
|
||||
}
|
||||
if e := gvalid.CheckMap(params, rules, msgs); e != nil {
|
||||
if e := gvalid.CheckMap(context.TODO(), params, rules, msgs); e != nil {
|
||||
g.Dump(e.Maps())
|
||||
}
|
||||
// map[passport:map[length:账号长度应当在6到16之间] password:map[same:两次密码输入不相等]]
|
||||
|
||||
28
.example/util/gvalid/gvalid_checkstructwithdata.go
Normal file
28
.example/util/gvalid/gvalid_checkstructwithdata.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `v:"required#请输入用户姓名"`
|
||||
Type int `v:"required#请选择用户类型"`
|
||||
}
|
||||
data := g.Map{
|
||||
"name": "john",
|
||||
}
|
||||
user := User{}
|
||||
if err := gconv.Scan(data, &user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err := gvalid.CheckStructWithData(context.TODO(), user, data, nil)
|
||||
// 也可以使用
|
||||
// err := g.Validator().Data(data).CheckStruct(user)
|
||||
if err != nil {
|
||||
g.Dump(err.Items())
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
@ -8,6 +9,6 @@ import (
|
||||
|
||||
func main() {
|
||||
g.I18n().SetLanguage("cn")
|
||||
err := gvalid.Check("", "required", nil)
|
||||
err := gvalid.Check(context.TODO(), "", "required", nil)
|
||||
fmt.Println(err.String())
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -17,7 +18,7 @@ func main() {
|
||||
ConfiemPassword: "",
|
||||
}
|
||||
|
||||
e := gvalid.CheckStruct(user, nil)
|
||||
e := gvalid.CheckStruct(context.TODO(), user, nil)
|
||||
g.Dump(e.Map())
|
||||
g.Dump(e.Maps())
|
||||
g.Dump(e.String())
|
||||
|
||||
38
.example/util/gvalid/gvalid_i18n.go
Normal file
38
.example/util/gvalid/gvalid_i18n.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `v:"required#ReuiredUserName"`
|
||||
Type int `v:"required#ReuiredUserType"`
|
||||
Project string `v:"size:10#MustSize"`
|
||||
}
|
||||
var (
|
||||
data = g.Map{
|
||||
"name": "john",
|
||||
"project": "gf",
|
||||
}
|
||||
user = User{}
|
||||
ctxEn = gi18n.WithLanguage(context.TODO(), "en")
|
||||
ctxCh = gi18n.WithLanguage(context.TODO(), "zh-CN")
|
||||
)
|
||||
|
||||
if err := gconv.Scan(data, &user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 英文
|
||||
if err := g.Validator().Ctx(ctxEn).Data(data).CheckStruct(user); err != nil {
|
||||
g.Dump(err.String())
|
||||
}
|
||||
// 中文
|
||||
if err := g.Validator().Ctx(ctxCh).Data(data).CheckStruct(user); err != nil {
|
||||
g.Dump(err.String())
|
||||
}
|
||||
}
|
||||
35
.example/util/gvalid/gvalid_i18n_http.go
Normal file
35
.example/util/gvalid/gvalid_i18n_http.go
Normal file
@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `v:"required#ReuiredUserName"`
|
||||
Type int `v:"required#ReuiredUserType"`
|
||||
Project string `v:"size:10#MustSize"`
|
||||
}
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
lang := r.GetString("lang", "zh-CN")
|
||||
r.SetCtx(gi18n.WithLanguage(r.Context(), lang))
|
||||
r.Middleware.Next()
|
||||
})
|
||||
group.GET("/validate", func(r *ghttp.Request) {
|
||||
var (
|
||||
err error
|
||||
user = User{}
|
||||
)
|
||||
if err = r.Parse(&user); err != nil {
|
||||
r.Response.WriteExit(err)
|
||||
}
|
||||
r.Response.WriteExit(user)
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -18,7 +19,7 @@ func main() {
|
||||
Pass2: "123",
|
||||
}
|
||||
|
||||
e := gvalid.CheckStruct(user, nil)
|
||||
e := gvalid.CheckStruct(context.TODO(), user, nil)
|
||||
g.Dump(e.String())
|
||||
g.Dump(e.FirstString())
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
@ -17,7 +18,7 @@ func main() {
|
||||
"password@required|length:6,16|same:password2#密码不能为空}|两次密码输入不相等",
|
||||
"password2@required|length:6,16#",
|
||||
}
|
||||
if e := gvalid.CheckMap(params, rules); e != nil {
|
||||
if e := gvalid.CheckMap(context.TODO(), params, rules); e != nil {
|
||||
fmt.Println(e.Map())
|
||||
fmt.Println(e.FirstItem())
|
||||
fmt.Println(e.FirstString())
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -20,7 +21,7 @@ func main() {
|
||||
}
|
||||
|
||||
// 使用结构体定义的校验规则和错误提示进行校验
|
||||
g.Dump(gvalid.CheckStruct(user, nil).Map())
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, nil).Map())
|
||||
|
||||
// 自定义校验规则和错误提示,对定义的特定校验规则和错误提示进行覆盖
|
||||
rules := map[string]string{
|
||||
@ -31,5 +32,5 @@ func main() {
|
||||
"password3": "名称不能为空",
|
||||
},
|
||||
}
|
||||
g.Dump(gvalid.CheckStruct(user, rules, msgs).Map())
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, rules, msgs).Map())
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -13,5 +14,5 @@ func main() {
|
||||
|
||||
user := &User{}
|
||||
|
||||
g.Dump(gvalid.CheckStruct(user, nil))
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, nil))
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -15,5 +16,5 @@ func main() {
|
||||
Pass: "1",
|
||||
}
|
||||
|
||||
g.Dump(gvalid.CheckStruct(user, nil).Maps())
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, nil).Maps())
|
||||
}
|
||||
|
||||
40
.example/util/gvalid/gvalid_struct_meta.go
Normal file
40
.example/util/gvalid/gvalid_struct_meta.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gmeta"
|
||||
)
|
||||
|
||||
type UserCreateReq struct {
|
||||
gmeta.Meta `v:"UserCreateReq"`
|
||||
Name string
|
||||
Pass string
|
||||
}
|
||||
|
||||
func UserCreateReqChecker(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
user := &UserCreateReq{}
|
||||
if v, ok := data.(*UserCreateReq); ok {
|
||||
user = v
|
||||
}
|
||||
// SELECT COUNT(*) FROM `user` WHERE `name` = xxx
|
||||
count, err := g.Model("user").Ctx(ctx).Where("name", user.Name).Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return gerror.Newf(`The name "%s" is already token`, user.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
user := &UserCreateReq{
|
||||
Name: "john",
|
||||
Pass: "123456",
|
||||
}
|
||||
err := g.Validator().RuleFunc("UserCreateReq", UserCreateReqChecker).CheckStruct(user)
|
||||
fmt.Println(err)
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
"gf.gvalid.required" = "字段不能为空"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
7
.example/util/gvalid/i18n/en.toml
Normal file
7
.example/util/gvalid/i18n/en.toml
Normal file
@ -0,0 +1,7 @@
|
||||
"gf.gvalid.required" = "字段不能为空"
|
||||
|
||||
|
||||
"ReuiredUserName" = "Please input user name"
|
||||
"ReuiredUserType" = "Please select user type"
|
||||
"MustSize" = "Size of :attribute must be :size"
|
||||
|
||||
16
.example/util/gvalid/i18n/zh-CN.toml
Normal file
16
.example/util/gvalid/i18n/zh-CN.toml
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
"gf.gvalid.required" = "字段不能为空"
|
||||
|
||||
"ReuiredUserName" = "请输入用户名称"
|
||||
"ReuiredUserType" = "请选择用户类型"
|
||||
"MustSize" = ":attribute长度必须为:size"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
<!-- 为更高效率地交流并解决问题,请按照以下模板提交issue,感谢! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 重要的事情说三遍! -->
|
||||
|
||||
### 1. 您当前使用的`Go`版本,及系统版本、系统架构?
|
||||
|
||||
|
||||
7
.github/ISSUE_TEMPLATE.MD
vendored
7
.github/ISSUE_TEMPLATE.MD
vendored
@ -1,5 +1,10 @@
|
||||
<!-- Please answer these questions before submitting your issue. Thanks! -->
|
||||
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 重要的事情说三遍! -->
|
||||
|
||||
### 1. What version of `Go` and system type/arch are you using?
|
||||
|
||||
<!--
|
||||
@ -13,7 +18,7 @@ What expect to see is like: `go 1.12, linux/amd64`
|
||||
<!-- You can find the GF version from your `go.mod`, or from the `version.go` in `GF` -->
|
||||
|
||||
|
||||
### 3. Can this issue be reproduced with the latest release?
|
||||
### 3. Can this issue be re-produced with the latest release?
|
||||
|
||||
|
||||
|
||||
|
||||
71
.github/workflows/go.yml
vendored
Normal file
71
.github/workflows/go.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
name: GoFrame CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
env:
|
||||
GF_DEBUG: 1
|
||||
|
||||
jobs:
|
||||
code-test:
|
||||
runs-on: ubuntu-latest
|
||||
# Service containers to run with `code-test`
|
||||
services:
|
||||
redis:
|
||||
image : redis
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
# Maps tcp port 6379 on service container to the host
|
||||
- 6379:6379
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_DATABASE : test
|
||||
MYSQL_ROOT_PASSWORD: 12345678
|
||||
ports:
|
||||
# Maps tcp port 3306 on service container to the host
|
||||
- 3306:3306
|
||||
|
||||
# strategy set
|
||||
strategy:
|
||||
matrix:
|
||||
go: ["1.14", "1.15", "1.16"]
|
||||
|
||||
steps:
|
||||
- name: Set Up Timezone
|
||||
uses: szenius/set-timezone@v1.0
|
||||
with:
|
||||
timezoneLinux: "Asia/Shanghai"
|
||||
|
||||
- name: Checkout Repositary
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Before Script
|
||||
run: |
|
||||
date
|
||||
find . -name "*.go" | xargs gofmt -w
|
||||
git diff --name-only --exit-code || exit 1
|
||||
sudo echo "127.0.0.1 local" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Run i386 Arch Test
|
||||
run: GOARCH=386 go test -v ./... || exit 1
|
||||
|
||||
- name: Run amd64 Arch Test
|
||||
run: GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic
|
||||
|
||||
- name: Report Coverage
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -14,5 +14,6 @@ bin/
|
||||
cbuild
|
||||
**/.DS_Store
|
||||
.vscode/
|
||||
go.sum
|
||||
.example/other/
|
||||
main
|
||||
gf
|
||||
@ -1,11 +1,12 @@
|
||||
os: linux
|
||||
arch: arm64-graviton2
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.13.x"
|
||||
- "1.14.x"
|
||||
- "1.15.x"
|
||||
- "1.16.x"
|
||||
|
||||
branches:
|
||||
only:
|
||||
@ -14,7 +15,7 @@ branches:
|
||||
- staging
|
||||
|
||||
env:
|
||||
- GF_DEBUG=1 GO111MODULE=on
|
||||
- TZ=Asia/Shanghai GF_DEBUG=1 GO111MODULE=on
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
||||
30
README.MD
30
README.MD
@ -1,7 +1,7 @@
|
||||
# GoFrame
|
||||
|
||||
[](https://godoc.org/github.com/gogf/gf)
|
||||
[](https://travis-ci.org/gogf/gf)
|
||||
[](https://github.com/gogf/gf/actions/workflows/go.yml)
|
||||
[](https://goreportcard.com/report/github.com/gogf/gf)
|
||||
[](https://codecov.io/gh/gogf/gf/branch/master)
|
||||
[](https://github.com/gogf/gf)
|
||||
@ -9,11 +9,8 @@
|
||||
|
||||
English | [简体中文](README_ZH.MD)
|
||||
|
||||
`GF(GoFrame)` is a modular, powerful, high-performance and enterprise-class application development framework
|
||||
of Golang. Providing a series of core components and dozens of practical modules, such as:
|
||||
cache, logging, containers, timer, resource, validator, database orm, etc.
|
||||
Supporting web server integrated with router, cookie, session, middleware, logger, configure,
|
||||
template, https, hooks, rewrites and many more features.
|
||||
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework
|
||||
of Golang.
|
||||
|
||||
> If you're a newbie to `Go`, you may consider `GoFrame` easy and great as `Laravel` in `PHP`, `SpringBoot` in `Java` or `Django` in `Python`.
|
||||
|
||||
@ -33,7 +30,7 @@ golang version >= 1.11
|
||||
|
||||
# Architecture
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/images/arch.png?v=12"/>
|
||||
<img src="https://goframe.org/download/attachments/1114119/arch.png"/>
|
||||
</div>
|
||||
|
||||
# Packages
|
||||
@ -53,17 +50,10 @@ The `Web` component performance of `GoFrame`, please refer to third-party projec
|
||||
|
||||
# Documentation
|
||||
|
||||
* 中文官网: https://goframe.org
|
||||
* GoDoc API: https://godoc.org/github.com/gogf/gf
|
||||
* 中文官网: [https://goframe.org](https://goframe.org/display/gf)
|
||||
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf](https://pkg.go.dev/github.com/gogf/gf)
|
||||
|
||||
|
||||
# Discussion
|
||||
- QQ Group:[116707870](//shang.qq.com/wpa/qunwpa?idkey=195f91eceeb5d7fa76009b7cd5a4641f70bf4897b7f5a520635eb26ff17adfe7)
|
||||
- WX Group:Add friend`389961817` in WeChat, commenting `GF`
|
||||
- Issues:https://github.com/gogf/gf/issues
|
||||
|
||||
> It's recommended learning `GoFrame` through its awesome source codes and API reference.
|
||||
|
||||
# License
|
||||
|
||||
`GF` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.
|
||||
@ -80,7 +70,7 @@ The `Web` component performance of `GoFrame`, please refer to third-party projec
|
||||
- [XiMaLaYa](https://www.ximalaya.com)
|
||||
- [ZYBang](https://www.zybang.com/)
|
||||
|
||||
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://github.com/gogf/gf/issues/168).
|
||||
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://goframe.org/pages/viewpage.action?pageId=1114415).
|
||||
|
||||
|
||||
# Contributors
|
||||
@ -90,7 +80,7 @@ This project exists thanks to all the people who contribute. [[Contributors](htt
|
||||
|
||||
# Donators
|
||||
|
||||
If you love `GF`, why not [buy developer a cup of coffee](https://itician.org/pages/viewpage.action?pageId=1115633)?
|
||||
If you love `GF`, why not [buy developer a cup of coffee](https://goframe.org/pages/viewpage.action?pageId=1115633)?
|
||||
|
||||
# Sponsors
|
||||
We appreciate any kind of sponsorship for `GF` development. If you've got some interesting, please contact WeChat `389961817` / Email `john@goframe.org`.
|
||||
@ -98,8 +88,8 @@ We appreciate any kind of sponsorship for `GF` development. If you've got some i
|
||||
|
||||
|
||||
# Thanks
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://itician.org/download/thumbnails/1114119/jetbrains.png?version=1&modificationDate=1608649325806&api=v2" height="120" alt="JetBrains"/></a>
|
||||
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://itician.org/download/thumbnails/1114119/u%3D605052180%2C3099422872%26fm%3D11%26gp%3D0.jpg?version=1&modificationDate=1608649343601&api=v2" height="120" alt="Atlassian"/></a>
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/download/thumbnails/1114119/jetbrains.png" height="120" alt="JetBrains"/></a>
|
||||
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://goframe.org/download/attachments/1114119/atlassian.jpg" height="120" alt="Atlassian"/></a>
|
||||
|
||||
|
||||
|
||||
|
||||
53
README_ZH.MD
53
README_ZH.MD
@ -1,6 +1,6 @@
|
||||
# GoFrame
|
||||
[](https://godoc.org/github.com/gogf/gf)
|
||||
[](https://travis-ci.org/gogf/gf)
|
||||
[](https://travis-ci.org/gogf/gf)
|
||||
[](https://goreportcard.com/report/github.com/gogf/gf)
|
||||
[](https://codecov.io/gh/gogf/gf/branch/master)
|
||||
[](https://github.com/gogf/gf)
|
||||
@ -8,24 +8,21 @@
|
||||
|
||||
[English](README.MD) | 简体中文
|
||||
|
||||
`GF(Go Frame)`是一款模块化、高性能、企业级的Go基础开发框架。
|
||||
实现了比较完善的基础设施建设以及开发工具链,提供了常用的基础开发模块,
|
||||
如:缓存、日志、队列、数组、集合、容器、定时器、命令行、内存锁、对象池、
|
||||
配置管理、资源管理、数据校验、数据编码、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信等等。
|
||||
并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、Middleware、服务注册、模板引擎等等,
|
||||
支持热重启、热更新、域名绑定、TLS/HTTPS、Rewrite等特性。
|
||||
`GoFrame`是一款模块化、高性能、企业级的Go基础开发框架。
|
||||
|
||||
> 如果您初识`Go`语言,您可以将`GoFrame`类似于`PHP`中的`Laravel`, `Java`中的`SpringBoot`或者`Python`中的`Django`。
|
||||
|
||||
# 特点
|
||||
* 模块化、松耦合设计;
|
||||
* 模块丰富、开箱即用;
|
||||
* 简便易用、易于维护;
|
||||
* 高代码质量、高单元测试覆盖率;
|
||||
* 社区活跃,大牛谦逊低调脾气好;
|
||||
* 详尽的开发文档及示例;
|
||||
* 完善的本地中文化支持;
|
||||
* 设计为团队及企业使用;
|
||||
* 模块化、松耦合
|
||||
* 模块丰富、开箱即用
|
||||
* 简洁易用、快速接入
|
||||
* 文档详尽、易于维护
|
||||
* 自顶向下、体系化设计
|
||||
* 统一框架、统一组件、降低选择成本
|
||||
* 开发规范、设计模式、代码分层模型
|
||||
* 强大便捷的开发工具链
|
||||
* 完善的本地中文化支持
|
||||
* 设计为团队及企业使用
|
||||
|
||||
# 地址
|
||||
- **主库**:https://github.com/gogf/gf
|
||||
@ -49,7 +46,7 @@ golang版本 >= 1.11
|
||||
|
||||
# 架构
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/images/arch.png?v=12"/>
|
||||
<img src="https://goframe.org/download/attachments/1114119/arch.png"/>
|
||||
</div>
|
||||
|
||||
# 模块
|
||||
@ -64,21 +61,14 @@ golang版本 >= 1.11
|
||||
|
||||
|
||||
# 性能
|
||||
|
||||
`Web`组件的性能测试,请参考第三方性能测试评估:https://github.com/the-benchmarker/web-frameworks
|
||||
大家较为感兴趣的`Web`组件性能测试,请参考第三方性能测试评估:https://github.com/the-benchmarker/web-frameworks
|
||||
|
||||
# 文档
|
||||
|
||||
开发文档:https://goframe.org
|
||||
官方站点:[https://goframe.org](https://goframe.org/display/gf)
|
||||
|
||||
接口文档:https://godoc.org/github.com/gogf/gf
|
||||
接口文档:[https://pkg.go.dev/github.com/gogf/gf](https://pkg.go.dev/github.com/gogf/gf)
|
||||
|
||||
# 帮助
|
||||
- QQ交流群:[116707870](//shang.qq.com/wpa/qunwpa?idkey=195f91eceeb5d7fa76009b7cd5a4641f70bf4897b7f5a520635eb26ff17adfe7)
|
||||
- WX交流群:微信添加`389961817`备注`GF`
|
||||
- 主库ISSUE:https://github.com/gogf/gf/issues
|
||||
|
||||
> 建议通过阅读`GoFrame`的源码以及API文档深度学习`GoFrame`,了解更多的精妙设计。
|
||||
|
||||
# 协议
|
||||
|
||||
@ -87,7 +77,7 @@ golang版本 >= 1.11
|
||||
# 用户
|
||||
|
||||
- [腾讯科技](https://www.tencent.com/)
|
||||
- [中兴科技](https://www.zte.com.cn/china/)
|
||||
- [中兴通讯](https://www.zte.com.cn/china/)
|
||||
- [蚂蚁金服](https://www.antfin.com/)
|
||||
- [医联科技](https://www.medlinker.com/)
|
||||
- [库币科技](https://www.kucoin.io/)
|
||||
@ -96,7 +86,7 @@ golang版本 >= 1.11
|
||||
- [喜马拉雅](https://www.ximalaya.com)
|
||||
- [作业帮](https://www.zybang.com/)
|
||||
|
||||
> 在这里只列举了部分知名的用户,如果您的企业或者产品正在使用`GoFrame`,欢迎到 [这里](https://github.com/gogf/gf/issues/168) 留言。
|
||||
> 在这里只列举了部分知名的用户,如果您的企业或者产品正在使用`GoFrame`,欢迎到 [这里](https://goframe.org/pages/viewpage.action?pageId=1114415) 留言。
|
||||
|
||||
# 贡献
|
||||
|
||||
@ -106,7 +96,7 @@ golang版本 >= 1.11
|
||||
|
||||
# 捐赠
|
||||
|
||||
如果您喜欢`GF`,要不给开发者 [来杯咖啡](https://itician.org/pages/viewpage.action?pageId=1115633) 吧!
|
||||
如果您喜欢`GF`,要不给开发者 [来杯咖啡](https://goframe.org/pages/viewpage.action?pageId=1115633) 吧!
|
||||
请在捐赠时备注您的`github`/`gitee`账号名称。
|
||||
|
||||
# 赞助
|
||||
@ -114,5 +104,6 @@ golang版本 >= 1.11
|
||||
赞助支持`GF`框架的快速研发,如果您感兴趣,请联系 微信 `389961817` / 邮件 `john@goframe.org`。
|
||||
|
||||
# 感谢
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://itician.org/download/thumbnails/1114119/jetbrains.png?version=1&modificationDate=1608649325806&api=v2" height="120" alt="JetBrains"/></a>
|
||||
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://itician.org/download/thumbnails/1114119/u%3D605052180%2C3099422872%26fm%3D11%26gp%3D0.jpg?version=1&modificationDate=1608649343601&api=v2" height="120" alt="Atlassian"/></a>
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/download/thumbnails/1114119/jetbrains.png" height="120" alt="JetBrains"/></a>
|
||||
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://goframe.org/download/attachments/1114119/atlassian.jpg" height="120" alt="Atlassian"/></a>
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -8,8 +8,9 @@ package garray
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gcode"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
@ -30,19 +31,19 @@ type Array struct {
|
||||
}
|
||||
|
||||
// New creates and returns an empty array.
|
||||
// The parameter <safe> is 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...)
|
||||
}
|
||||
|
||||
// See New.
|
||||
// NewArray is alias of New, please see New.
|
||||
func NewArray(safe ...bool) *Array {
|
||||
return NewArraySize(0, 0, safe...)
|
||||
}
|
||||
|
||||
// NewArraySize create and returns an array with given size and cap.
|
||||
// The parameter <safe> is 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{
|
||||
@ -51,8 +52,8 @@ func NewArraySize(size int, cap int, safe ...bool) *Array {
|
||||
}
|
||||
}
|
||||
|
||||
// NewArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
// NewArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewArrayRange(start, end, step int, safe ...bool) *Array {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
@ -66,18 +67,20 @@ func NewArrayRange(start, end, step int, safe ...bool) *Array {
|
||||
return NewArrayFrom(slice, safe...)
|
||||
}
|
||||
|
||||
// NewFrom is alias of NewArrayFrom.
|
||||
// See NewArrayFrom.
|
||||
func NewFrom(array []interface{}, safe ...bool) *Array {
|
||||
return NewArrayFrom(array, safe...)
|
||||
}
|
||||
|
||||
// NewFromCopy is alias of NewArrayFromCopy.
|
||||
// See NewArrayFromCopy.
|
||||
func NewFromCopy(array []interface{}, safe ...bool) *Array {
|
||||
return NewArrayFromCopy(array, safe...)
|
||||
}
|
||||
|
||||
// NewArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewArrayFrom creates and returns an array with given slice `array`.
|
||||
// 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{
|
||||
@ -86,8 +89,8 @@ func NewArrayFrom(array []interface{}, safe ...bool) *Array {
|
||||
}
|
||||
}
|
||||
|
||||
// NewArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewArrayFromCopy creates and returns an array from a copy of given slice `array`.
|
||||
// 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))
|
||||
@ -98,8 +101,15 @@ func NewArrayFromCopy(array []interface{}, safe ...bool) *Array {
|
||||
}
|
||||
}
|
||||
|
||||
// At returns the value by the specified index.
|
||||
// If the given `index` is out of range of the array, it returns `nil`.
|
||||
func (a *Array) At(index int) (value interface{}) {
|
||||
value, _ = a.Get(index)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *Array) Get(index int) (value interface{}, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -114,13 +124,13 @@ func (a *Array) Set(index int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
a.array[index] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
// SetArray sets the underlying slice array with the given `array`.
|
||||
func (a *Array) SetArray(array []interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -128,7 +138,7 @@ func (a *Array) SetArray(array []interface{}) *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// Replace replaces the array items by given <array> from the beginning of array.
|
||||
// Replace replaces the array items by given `array` from the beginning of array.
|
||||
func (a *Array) Replace(array []interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -152,7 +162,7 @@ func (a *Array) Sum() (sum int) {
|
||||
return
|
||||
}
|
||||
|
||||
// SortFunc sorts the array by custom function <less>.
|
||||
// SortFunc sorts the array by custom function `less`.
|
||||
func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -162,12 +172,12 @@ func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertBefore inserts the <value> to the front of <index>.
|
||||
// InsertBefore inserts the `value` to the front of `index`.
|
||||
func (a *Array) InsertBefore(index int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]interface{}{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
@ -175,12 +185,12 @@ func (a *Array) InsertBefore(index int, value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
// InsertAfter inserts the `value` to the back of `index`.
|
||||
func (a *Array) InsertAfter(index int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]interface{}{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
@ -189,7 +199,7 @@ func (a *Array) InsertAfter(index int, value interface{}) error {
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *Array) Remove(index int) (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -247,14 +257,14 @@ func (a *Array) PushRight(value ...interface{}) *Array {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *Array) PopRand() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// PopRands randomly pops and returns `size` items out of array.
|
||||
func (a *Array) PopRands(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -272,7 +282,7 @@ func (a *Array) PopRands(size int) []interface{} {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *Array) PopLeft() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -285,7 +295,7 @@ func (a *Array) PopLeft() (value interface{}, found bool) {
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *Array) PopRight() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -298,7 +308,7 @@ func (a *Array) PopRight() (value interface{}, found bool) {
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// PopLefts pops and returns `size` items from the beginning of array.
|
||||
func (a *Array) PopLefts(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -315,7 +325,7 @@ func (a *Array) PopLefts(size int) []interface{} {
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// PopRights pops and returns `size` items from the end of array.
|
||||
func (a *Array) PopRights(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -337,8 +347,8 @@ func (a *Array) PopRights(size int) []interface{} {
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
//
|
||||
// If <end> is negative, then the offset will start from the end of array.
|
||||
// If <end> is omitted, then the sequence will have everything from start up
|
||||
// If `end` is negative, then the offset will start from the end of array.
|
||||
// If `end` is omitted, then the sequence will have everything from start up
|
||||
// until the end of the array.
|
||||
func (a *Array) Range(start int, end ...int) []interface{} {
|
||||
a.mu.RLock()
|
||||
@ -364,7 +374,7 @@ func (a *Array) Range(start int, end ...int) []interface{} {
|
||||
}
|
||||
|
||||
// SubSlice returns a slice of elements from the array as specified
|
||||
// by the <offset> and <size> parameters.
|
||||
// by the `offset` and `size` parameters.
|
||||
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
|
||||
//
|
||||
// If offset is non-negative, the sequence will start at that offset in the array.
|
||||
@ -413,7 +423,7 @@ func (a *Array) SubSlice(offset int, length ...int) []interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// See PushRight.
|
||||
// Append is alias of PushRight, please See PushRight.
|
||||
func (a *Array) Append(value ...interface{}) *Array {
|
||||
a.PushRight(value...)
|
||||
return a
|
||||
@ -471,7 +481,7 @@ func (a *Array) Contains(value interface{}) bool {
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// Search searches array by `value`, returns the index of `value`,
|
||||
// or returns -1 if not exists.
|
||||
func (a *Array) Search(value interface{}) int {
|
||||
a.mu.RLock()
|
||||
@ -506,7 +516,7 @@ func (a *Array) Unique() *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// LockFunc locks writing by callback function <f>.
|
||||
// LockFunc locks writing by callback function `f`.
|
||||
func (a *Array) LockFunc(f func(array []interface{})) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -514,7 +524,7 @@ func (a *Array) LockFunc(f func(array []interface{})) *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// RLockFunc locks reading by callback function <f>.
|
||||
// RLockFunc locks reading by callback function `f`.
|
||||
func (a *Array) RLockFunc(f func(array []interface{})) *Array {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -522,21 +532,21 @@ func (a *Array) RLockFunc(f func(array []interface{})) *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// Merge merges <array> into current array.
|
||||
// The parameter <array> can be any garray or slice type.
|
||||
// Merge merges `array` into current array.
|
||||
// The parameter `array` can be any garray or slice type.
|
||||
// The difference between Merge and Append is Append supports only specified slice type,
|
||||
// but Merge supports more parameter types.
|
||||
func (a *Array) Merge(array interface{}) *Array {
|
||||
return a.Append(gconv.Interfaces(array)...)
|
||||
}
|
||||
|
||||
// Fill fills an array with num entries of the value <value>,
|
||||
// keys starting at the <startIndex> parameter.
|
||||
// Fill fills an array with num entries of the value `value`,
|
||||
// keys starting at the `startIndex` parameter.
|
||||
func (a *Array) Fill(startIndex int, num int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if startIndex < 0 || startIndex > len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", startIndex, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
|
||||
}
|
||||
for i := startIndex; i < startIndex+num; i++ {
|
||||
if i > len(a.array)-1 {
|
||||
@ -549,7 +559,7 @@ func (a *Array) Fill(startIndex int, num int, value interface{}) error {
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
// the size of each array is determined by <size>.
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (a *Array) Chunk(size int) [][]interface{} {
|
||||
if size < 1 {
|
||||
@ -571,9 +581,9 @@ func (a *Array) Chunk(size int) [][]interface{} {
|
||||
return n
|
||||
}
|
||||
|
||||
// Pad pads array to the specified length with <value>.
|
||||
// Pad pads array to the specified length with `value`.
|
||||
// If size is positive then the array is padded on the right, or negative on the left.
|
||||
// If the absolute value of <size> is less than or equal to the length of the array
|
||||
// If the absolute value of `size` is less than or equal to the length of the array
|
||||
// then no padding takes place.
|
||||
func (a *Array) Pad(size int, val interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
@ -608,7 +618,7 @@ func (a *Array) Rand() (value interface{}, found bool) {
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
// Rands randomly returns `size` items from array(no deleting).
|
||||
func (a *Array) Rands(size int) []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -642,7 +652,7 @@ func (a *Array) Reverse() *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
// Join joins array elements with a string `glue`.
|
||||
func (a *Array) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -675,8 +685,8 @@ func (a *Array) Iterator(f func(k int, v interface{}) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *Array) IteratorAsc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -687,8 +697,8 @@ func (a *Array) IteratorAsc(f func(k int, v interface{}) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *Array) IteratorDesc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -736,7 +746,7 @@ func (a *Array) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -748,7 +758,7 @@ func (a *Array) UnmarshalValue(value interface{}) error {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceAny(value)
|
||||
}
|
||||
@ -784,7 +794,7 @@ func (a *Array) FilterEmpty() *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function <f> to every item of array.
|
||||
// Walk applies a user supplied function `f` to every item of array.
|
||||
func (a *Array) Walk(f func(value interface{}) interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -8,8 +8,9 @@ package garray
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gcode"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"math"
|
||||
"sort"
|
||||
@ -28,14 +29,14 @@ type IntArray struct {
|
||||
}
|
||||
|
||||
// NewIntArray creates and returns an empty array.
|
||||
// The parameter <safe> is 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> is 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{
|
||||
@ -44,8 +45,8 @@ func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
// NewIntArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
@ -59,8 +60,8 @@ func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
|
||||
return NewIntArrayFrom(slice, safe...)
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewIntArrayFrom creates and returns an array with given slice `array`.
|
||||
// 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{
|
||||
@ -69,8 +70,8 @@ func NewIntArrayFrom(array []int, safe ...bool) *IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewIntArrayFromCopy creates and returns an array from a copy of given slice `array`.
|
||||
// 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))
|
||||
@ -81,8 +82,15 @@ func NewIntArrayFromCopy(array []int, safe ...bool) *IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// At returns the value by the specified index.
|
||||
// If the given `index` is out of range of the array, it returns `0`.
|
||||
func (a *IntArray) At(index int) (value int) {
|
||||
value, _ = a.Get(index)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *IntArray) Get(index int) (value int, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -97,13 +105,13 @@ func (a *IntArray) Set(index int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
a.array[index] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
// SetArray sets the underlying slice array with the given `array`.
|
||||
func (a *IntArray) SetArray(array []int) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -111,7 +119,7 @@ func (a *IntArray) SetArray(array []int) *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Replace replaces the array items by given <array> from the beginning of array.
|
||||
// Replace replaces the array items by given `array` from the beginning of array.
|
||||
func (a *IntArray) Replace(array []int) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -136,16 +144,13 @@ func (a *IntArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort in increasing order(default) or decreasing order.
|
||||
// The parameter `reverse` controls whether sort in increasing order(default) or decreasing order.
|
||||
func (a *IntArray) Sort(reverse ...bool) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(reverse) > 0 && reverse[0] {
|
||||
sort.Slice(a.array, func(i, j int) bool {
|
||||
if a.array[i] < a.array[j] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return a.array[i] >= a.array[j]
|
||||
})
|
||||
} else {
|
||||
sort.Ints(a.array)
|
||||
@ -153,7 +158,7 @@ func (a *IntArray) Sort(reverse ...bool) *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// SortFunc sorts the array by custom function <less>.
|
||||
// SortFunc sorts the array by custom function `less`.
|
||||
func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -163,12 +168,12 @@ func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertBefore inserts the <value> to the front of <index>.
|
||||
// InsertBefore inserts the `value` to the front of `index`.
|
||||
func (a *IntArray) InsertBefore(index int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]int{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
@ -176,12 +181,12 @@ func (a *IntArray) InsertBefore(index int, value int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
// InsertAfter inserts the `value` to the back of `index`.
|
||||
func (a *IntArray) InsertAfter(index int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]int{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
@ -190,7 +195,7 @@ func (a *IntArray) InsertAfter(index int, value int) error {
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *IntArray) Remove(index int) (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -248,7 +253,7 @@ func (a *IntArray) PushRight(value ...int) *IntArray {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *IntArray) PopLeft() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -261,7 +266,7 @@ func (a *IntArray) PopLeft() (value int, found bool) {
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *IntArray) PopRight() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -275,16 +280,16 @@ func (a *IntArray) PopRight() (value int, found bool) {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *IntArray) PopRand() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRands randomly pops and returns `size` items out of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *IntArray) PopRands(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -301,9 +306,9 @@ func (a *IntArray) PopRands(size int) []int {
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopLefts pops and returns `size` items from the beginning of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *IntArray) PopLefts(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -320,9 +325,9 @@ func (a *IntArray) PopLefts(size int) []int {
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRights pops and returns `size` items from the end of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *IntArray) PopRights(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -344,8 +349,8 @@ func (a *IntArray) PopRights(size int) []int {
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
//
|
||||
// If <end> is negative, then the offset will start from the end of array.
|
||||
// If <end> is omitted, then the sequence will have everything from start up
|
||||
// If `end` is negative, then the offset will start from the end of array.
|
||||
// If `end` is omitted, then the sequence will have everything from start up
|
||||
// until the end of the array.
|
||||
func (a *IntArray) Range(start int, end ...int) []int {
|
||||
a.mu.RLock()
|
||||
@ -371,7 +376,7 @@ func (a *IntArray) Range(start int, end ...int) []int {
|
||||
}
|
||||
|
||||
// SubSlice returns a slice of elements from the array as specified
|
||||
// by the <offset> and <size> parameters.
|
||||
// by the `offset` and `size` parameters.
|
||||
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
|
||||
//
|
||||
// If offset is non-negative, the sequence will start at that offset in the array.
|
||||
@ -420,7 +425,7 @@ func (a *IntArray) SubSlice(offset int, length ...int) []int {
|
||||
}
|
||||
}
|
||||
|
||||
// See PushRight.
|
||||
// Append is alias of PushRight,please See PushRight.
|
||||
func (a *IntArray) Append(value ...int) *IntArray {
|
||||
a.mu.Lock()
|
||||
a.array = append(a.array, value...)
|
||||
@ -487,7 +492,7 @@ func (a *IntArray) Contains(value int) bool {
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// Search searches array by `value`, returns the index of `value`,
|
||||
// or returns -1 if not exists.
|
||||
func (a *IntArray) Search(value int) int {
|
||||
a.mu.RLock()
|
||||
@ -522,7 +527,7 @@ func (a *IntArray) Unique() *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// LockFunc locks writing by callback function <f>.
|
||||
// LockFunc locks writing by callback function `f`.
|
||||
func (a *IntArray) LockFunc(f func(array []int)) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -530,7 +535,7 @@ func (a *IntArray) LockFunc(f func(array []int)) *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// RLockFunc locks reading by callback function <f>.
|
||||
// RLockFunc locks reading by callback function `f`.
|
||||
func (a *IntArray) RLockFunc(f func(array []int)) *IntArray {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -538,21 +543,21 @@ func (a *IntArray) RLockFunc(f func(array []int)) *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Merge merges <array> into current array.
|
||||
// The parameter <array> can be any garray or slice type.
|
||||
// Merge merges `array` into current array.
|
||||
// The parameter `array` can be any garray or slice type.
|
||||
// The difference between Merge and Append is Append supports only specified slice type,
|
||||
// but Merge supports more parameter types.
|
||||
func (a *IntArray) Merge(array interface{}) *IntArray {
|
||||
return a.Append(gconv.Ints(array)...)
|
||||
}
|
||||
|
||||
// Fill fills an array with num entries of the value <value>,
|
||||
// keys starting at the <startIndex> parameter.
|
||||
// Fill fills an array with num entries of the value `value`,
|
||||
// keys starting at the `startIndex` parameter.
|
||||
func (a *IntArray) Fill(startIndex int, num int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if startIndex < 0 || startIndex > len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", startIndex, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
|
||||
}
|
||||
for i := startIndex; i < startIndex+num; i++ {
|
||||
if i > len(a.array)-1 {
|
||||
@ -565,7 +570,7 @@ func (a *IntArray) Fill(startIndex int, num int, value int) error {
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
// the size of each array is determined by <size>.
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (a *IntArray) Chunk(size int) [][]int {
|
||||
if size < 1 {
|
||||
@ -587,9 +592,9 @@ func (a *IntArray) Chunk(size int) [][]int {
|
||||
return n
|
||||
}
|
||||
|
||||
// Pad pads array to the specified length with <value>.
|
||||
// Pad pads array to the specified length with `value`.
|
||||
// If size is positive then the array is padded on the right, or negative on the left.
|
||||
// If the absolute value of <size> is less than or equal to the length of the array
|
||||
// If the absolute value of `size` is less than or equal to the length of the array
|
||||
// then no padding takes place.
|
||||
func (a *IntArray) Pad(size int, value int) *IntArray {
|
||||
a.mu.Lock()
|
||||
@ -624,7 +629,7 @@ func (a *IntArray) Rand() (value int, found bool) {
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
// Rands randomly returns `size` items from array(no deleting).
|
||||
func (a *IntArray) Rands(size int) []int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -658,7 +663,7 @@ func (a *IntArray) Reverse() *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
// Join joins array elements with a string `glue`.
|
||||
func (a *IntArray) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -691,8 +696,8 @@ func (a *IntArray) Iterator(f func(k int, v int) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *IntArray) IteratorAsc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -703,8 +708,8 @@ func (a *IntArray) IteratorAsc(f func(k int, v int) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *IntArray) IteratorDesc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -735,7 +740,7 @@ func (a *IntArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -747,7 +752,7 @@ func (a *IntArray) UnmarshalValue(value interface{}) error {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceInt(value)
|
||||
}
|
||||
@ -768,7 +773,7 @@ func (a *IntArray) FilterEmpty() *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function <f> to every item of array.
|
||||
// Walk applies a user supplied function `f` to every item of array.
|
||||
func (a *IntArray) Walk(f func(value int) int) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -8,8 +8,8 @@ package garray
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gcode"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"math"
|
||||
@ -30,14 +30,14 @@ type StrArray struct {
|
||||
}
|
||||
|
||||
// NewStrArray creates and returns an empty array.
|
||||
// The parameter <safe> is 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> is 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{
|
||||
@ -46,8 +46,8 @@ func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewStrArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewStrArrayFrom creates and returns an array with given slice `array`.
|
||||
// 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{
|
||||
@ -56,8 +56,8 @@ func NewStrArrayFrom(array []string, safe ...bool) *StrArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewStrArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewStrArrayFromCopy creates and returns an array from a copy of given slice `array`.
|
||||
// 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))
|
||||
@ -68,8 +68,15 @@ func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {
|
||||
}
|
||||
}
|
||||
|
||||
// At returns the value by the specified index.
|
||||
// If the given `index` is out of range of the array, it returns an empty string.
|
||||
func (a *StrArray) At(index int) (value string) {
|
||||
value, _ = a.Get(index)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *StrArray) Get(index int) (value string, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -84,13 +91,13 @@ func (a *StrArray) Set(index int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
a.array[index] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
// SetArray sets the underlying slice array with the given `array`.
|
||||
func (a *StrArray) SetArray(array []string) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -98,7 +105,7 @@ func (a *StrArray) SetArray(array []string) *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Replace replaces the array items by given <array> from the beginning of array.
|
||||
// Replace replaces the array items by given `array` from the beginning of array.
|
||||
func (a *StrArray) Replace(array []string) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -123,17 +130,14 @@ func (a *StrArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort
|
||||
// The parameter `reverse` controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *StrArray) Sort(reverse ...bool) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(reverse) > 0 && reverse[0] {
|
||||
sort.Slice(a.array, func(i, j int) bool {
|
||||
if strings.Compare(a.array[i], a.array[j]) < 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return strings.Compare(a.array[i], a.array[j]) >= 0
|
||||
})
|
||||
} else {
|
||||
sort.Strings(a.array)
|
||||
@ -141,7 +145,7 @@ func (a *StrArray) Sort(reverse ...bool) *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// SortFunc sorts the array by custom function <less>.
|
||||
// SortFunc sorts the array by custom function `less`.
|
||||
func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -151,12 +155,12 @@ func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertBefore inserts the <value> to the front of <index>.
|
||||
// InsertBefore inserts the `value` to the front of `index`.
|
||||
func (a *StrArray) InsertBefore(index int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]string{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
@ -164,12 +168,12 @@ func (a *StrArray) InsertBefore(index int, value string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
// InsertAfter inserts the `value` to the back of `index`.
|
||||
func (a *StrArray) InsertAfter(index int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]string{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
@ -178,7 +182,7 @@ func (a *StrArray) InsertAfter(index int, value string) error {
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *StrArray) Remove(index int) (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -236,7 +240,7 @@ func (a *StrArray) PushRight(value ...string) *StrArray {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *StrArray) PopLeft() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -249,7 +253,7 @@ func (a *StrArray) PopLeft() (value string, found bool) {
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *StrArray) PopRight() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -263,16 +267,16 @@ func (a *StrArray) PopRight() (value string, found bool) {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *StrArray) PopRand() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRands randomly pops and returns `size` items out of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *StrArray) PopRands(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -289,9 +293,9 @@ func (a *StrArray) PopRands(size int) []string {
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopLefts pops and returns `size` items from the beginning of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *StrArray) PopLefts(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -308,9 +312,9 @@ func (a *StrArray) PopLefts(size int) []string {
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRights pops and returns `size` items from the end of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *StrArray) PopRights(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -332,8 +336,8 @@ func (a *StrArray) PopRights(size int) []string {
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
//
|
||||
// If <end> is negative, then the offset will start from the end of array.
|
||||
// If <end> is omitted, then the sequence will have everything from start up
|
||||
// If `end` is negative, then the offset will start from the end of array.
|
||||
// If `end` is omitted, then the sequence will have everything from start up
|
||||
// until the end of the array.
|
||||
func (a *StrArray) Range(start int, end ...int) []string {
|
||||
a.mu.RLock()
|
||||
@ -359,7 +363,7 @@ func (a *StrArray) Range(start int, end ...int) []string {
|
||||
}
|
||||
|
||||
// SubSlice returns a slice of elements from the array as specified
|
||||
// by the <offset> and <size> parameters.
|
||||
// by the `offset` and `size` parameters.
|
||||
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
|
||||
//
|
||||
// If offset is non-negative, the sequence will start at that offset in the array.
|
||||
@ -408,7 +412,7 @@ func (a *StrArray) SubSlice(offset int, length ...int) []string {
|
||||
}
|
||||
}
|
||||
|
||||
// See PushRight.
|
||||
// Append is alias of PushRight,please See PushRight.
|
||||
func (a *StrArray) Append(value ...string) *StrArray {
|
||||
a.mu.Lock()
|
||||
a.array = append(a.array, value...)
|
||||
@ -491,7 +495,7 @@ func (a *StrArray) ContainsI(value string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// Search searches array by `value`, returns the index of `value`,
|
||||
// or returns -1 if not exists.
|
||||
func (a *StrArray) Search(value string) int {
|
||||
a.mu.RLock()
|
||||
@ -526,7 +530,7 @@ func (a *StrArray) Unique() *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// LockFunc locks writing by callback function <f>.
|
||||
// LockFunc locks writing by callback function `f`.
|
||||
func (a *StrArray) LockFunc(f func(array []string)) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -534,7 +538,7 @@ func (a *StrArray) LockFunc(f func(array []string)) *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// RLockFunc locks reading by callback function <f>.
|
||||
// RLockFunc locks reading by callback function `f`.
|
||||
func (a *StrArray) RLockFunc(f func(array []string)) *StrArray {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -542,21 +546,21 @@ func (a *StrArray) RLockFunc(f func(array []string)) *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Merge merges <array> into current array.
|
||||
// The parameter <array> can be any garray or slice type.
|
||||
// Merge merges `array` into current array.
|
||||
// The parameter `array` can be any garray or slice type.
|
||||
// The difference between Merge and Append is Append supports only specified slice type,
|
||||
// but Merge supports more parameter types.
|
||||
func (a *StrArray) Merge(array interface{}) *StrArray {
|
||||
return a.Append(gconv.Strings(array)...)
|
||||
}
|
||||
|
||||
// Fill fills an array with num entries of the value <value>,
|
||||
// keys starting at the <startIndex> parameter.
|
||||
// Fill fills an array with num entries of the value `value`,
|
||||
// keys starting at the `startIndex` parameter.
|
||||
func (a *StrArray) Fill(startIndex int, num int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if startIndex < 0 || startIndex > len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", startIndex, len(a.array)))
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
|
||||
}
|
||||
for i := startIndex; i < startIndex+num; i++ {
|
||||
if i > len(a.array)-1 {
|
||||
@ -569,7 +573,7 @@ func (a *StrArray) Fill(startIndex int, num int, value string) error {
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
// the size of each array is determined by <size>.
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (a *StrArray) Chunk(size int) [][]string {
|
||||
if size < 1 {
|
||||
@ -591,9 +595,9 @@ func (a *StrArray) Chunk(size int) [][]string {
|
||||
return n
|
||||
}
|
||||
|
||||
// Pad pads array to the specified length with <value>.
|
||||
// Pad pads array to the specified length with `value`.
|
||||
// If size is positive then the array is padded on the right, or negative on the left.
|
||||
// If the absolute value of <size> is less than or equal to the length of the array
|
||||
// If the absolute value of `size` is less than or equal to the length of the array
|
||||
// then no padding takes place.
|
||||
func (a *StrArray) Pad(size int, value string) *StrArray {
|
||||
a.mu.Lock()
|
||||
@ -628,7 +632,7 @@ func (a *StrArray) Rand() (value string, found bool) {
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
// Rands randomly returns `size` items from array(no deleting).
|
||||
func (a *StrArray) Rands(size int) []string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -662,7 +666,7 @@ func (a *StrArray) Reverse() *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
// Join joins array elements with a string `glue`.
|
||||
func (a *StrArray) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -695,8 +699,8 @@ func (a *StrArray) Iterator(f func(k int, v string) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -707,8 +711,8 @@ func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -750,7 +754,7 @@ func (a *StrArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -762,7 +766,7 @@ func (a *StrArray) UnmarshalValue(value interface{}) error {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceStr(value)
|
||||
}
|
||||
@ -783,7 +787,7 @@ func (a *StrArray) FilterEmpty() *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function <f> to every item of array.
|
||||
// Walk applies a user supplied function `f` to every item of array.
|
||||
func (a *StrArray) Walk(f func(value string) string) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -34,8 +34,8 @@ type SortedArray struct {
|
||||
}
|
||||
|
||||
// NewSortedArray creates and returns an empty sorted array.
|
||||
// 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,
|
||||
// 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; the v1 will be inserted before v2;
|
||||
// if it returns value = 0, means v1 = v2; the v1 will be replaced by v2;
|
||||
// if it returns value > 0, means v1 > v2; the v1 will be inserted after v2;
|
||||
@ -44,7 +44,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> is 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{
|
||||
@ -54,8 +54,8 @@ func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
// NewSortedArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
@ -69,8 +69,8 @@ func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{})
|
||||
return NewSortedArrayFrom(slice, comparator, safe...)
|
||||
}
|
||||
|
||||
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewSortedArrayFrom creates and returns an sorted array with given slice `array`.
|
||||
// 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...)
|
||||
@ -81,8 +81,8 @@ func NewSortedArrayFrom(array []interface{}, comparator func(a, b interface{}) i
|
||||
return a
|
||||
}
|
||||
|
||||
// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.
|
||||
// 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))
|
||||
@ -90,7 +90,14 @@ func NewSortedArrayFromCopy(array []interface{}, comparator func(a, b interface{
|
||||
return NewSortedArrayFrom(newArray, comparator, safe...)
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
// At returns the value by the specified index.
|
||||
// If the given `index` is out of range of the array, it returns `nil`.
|
||||
func (a *SortedArray) At(index int) (value interface{}) {
|
||||
value, _ = a.Get(index)
|
||||
return
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given `array`.
|
||||
func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -113,7 +120,7 @@ func (a *SortedArray) SetComparator(comparator func(a, b interface{}) int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort
|
||||
// The parameter `reverse` controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *SortedArray) Sort() *SortedArray {
|
||||
a.mu.Lock()
|
||||
@ -149,15 +156,13 @@ func (a *SortedArray) Append(values ...interface{}) *SortedArray {
|
||||
if cmp > 0 {
|
||||
index++
|
||||
}
|
||||
rear := append([]interface{}{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
a.array = append(a.array[:index], append([]interface{}{value}, a.array[index:]...)...)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *SortedArray) Get(index int) (value interface{}, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -168,7 +173,7 @@ func (a *SortedArray) Get(index int) (value interface{}, found bool) {
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *SortedArray) Remove(index int) (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -209,7 +214,7 @@ func (a *SortedArray) RemoveValue(value interface{}) bool {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedArray) PopLeft() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -222,7 +227,7 @@ func (a *SortedArray) PopLeft() (value interface{}, found bool) {
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedArray) PopRight() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -236,14 +241,14 @@ func (a *SortedArray) PopRight() (value interface{}, found bool) {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedArray) PopRand() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// PopRands randomly pops and returns `size` items out of array.
|
||||
func (a *SortedArray) PopRands(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -260,7 +265,7 @@ func (a *SortedArray) PopRands(size int) []interface{} {
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// PopLefts pops and returns `size` items from the beginning of array.
|
||||
func (a *SortedArray) PopLefts(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -277,7 +282,7 @@ func (a *SortedArray) PopLefts(size int) []interface{} {
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// PopRights pops and returns `size` items from the end of array.
|
||||
func (a *SortedArray) PopRights(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -299,8 +304,8 @@ func (a *SortedArray) PopRights(size int) []interface{} {
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
//
|
||||
// If <end> is negative, then the offset will start from the end of array.
|
||||
// If <end> is omitted, then the sequence will have everything from start up
|
||||
// If `end` is negative, then the offset will start from the end of array.
|
||||
// If `end` is omitted, then the sequence will have everything from start up
|
||||
// until the end of the array.
|
||||
func (a *SortedArray) Range(start int, end ...int) []interface{} {
|
||||
a.mu.RLock()
|
||||
@ -326,7 +331,7 @@ func (a *SortedArray) Range(start int, end ...int) []interface{} {
|
||||
}
|
||||
|
||||
// SubSlice returns a slice of elements from the array as specified
|
||||
// by the <offset> and <size> parameters.
|
||||
// by the `offset` and `size` parameters.
|
||||
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
|
||||
//
|
||||
// If offset is non-negative, the sequence will start at that offset in the array.
|
||||
@ -419,7 +424,7 @@ func (a *SortedArray) Contains(value interface{}) bool {
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// Search searches array by `value`, returns the index of `value`,
|
||||
// or returns -1 if not exists.
|
||||
func (a *SortedArray) Search(value interface{}) (index int) {
|
||||
if i, r := a.binSearch(value, true); r == 0 {
|
||||
@ -430,9 +435,9 @@ func (a *SortedArray) Search(value interface{}) (index int) {
|
||||
|
||||
// Binary search.
|
||||
// It returns the last compared index and the result.
|
||||
// If <result> equals to 0, it means the value at <index> is equals to <value>.
|
||||
// If <result> lesser than 0, it means the value at <index> is lesser than <value>.
|
||||
// If <result> greater than 0, it means the value at <index> is greater than <value>.
|
||||
// If `result` equals to 0, it means the value at `index` is equals to `value`.
|
||||
// If `result` lesser than 0, it means the value at `index` is lesser than `value`.
|
||||
// If `result` greater than 0, it means the value at `index` is greater than `value`.
|
||||
func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result int) {
|
||||
if lock {
|
||||
a.mu.RLock()
|
||||
@ -446,7 +451,7 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result
|
||||
mid := 0
|
||||
cmp := -2
|
||||
for min <= max {
|
||||
mid = min + int((max-min)/2)
|
||||
mid = min + (max-min)/2
|
||||
cmp = a.getComparator()(value, a.array[mid])
|
||||
switch {
|
||||
case cmp < 0:
|
||||
@ -512,7 +517,7 @@ func (a *SortedArray) Clear() *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// LockFunc locks writing by callback function <f>.
|
||||
// LockFunc locks writing by callback function `f`.
|
||||
func (a *SortedArray) LockFunc(f func(array []interface{})) *SortedArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -526,7 +531,7 @@ func (a *SortedArray) LockFunc(f func(array []interface{})) *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// RLockFunc locks reading by callback function <f>.
|
||||
// RLockFunc locks reading by callback function `f`.
|
||||
func (a *SortedArray) RLockFunc(f func(array []interface{})) *SortedArray {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -534,8 +539,8 @@ func (a *SortedArray) RLockFunc(f func(array []interface{})) *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Merge merges <array> into current array.
|
||||
// The parameter <array> can be any garray or slice type.
|
||||
// Merge merges `array` into current array.
|
||||
// The parameter `array` can be any garray or slice type.
|
||||
// The difference between Merge and Append is Append supports only specified slice type,
|
||||
// but Merge supports more parameter types.
|
||||
func (a *SortedArray) Merge(array interface{}) *SortedArray {
|
||||
@ -543,7 +548,7 @@ func (a *SortedArray) Merge(array interface{}) *SortedArray {
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
// the size of each array is determined by <size>.
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (a *SortedArray) Chunk(size int) [][]interface{} {
|
||||
if size < 1 {
|
||||
@ -575,7 +580,7 @@ func (a *SortedArray) Rand() (value interface{}, found bool) {
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
// Rands randomly returns `size` items from array(no deleting).
|
||||
func (a *SortedArray) Rands(size int) []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -589,7 +594,7 @@ func (a *SortedArray) Rands(size int) []interface{} {
|
||||
return array
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
// Join joins array elements with a string `glue`.
|
||||
func (a *SortedArray) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -622,8 +627,8 @@ func (a *SortedArray) Iterator(f func(k int, v interface{}) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedArray) IteratorAsc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -634,8 +639,8 @@ func (a *SortedArray) IteratorAsc(f func(k int, v interface{}) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedArray) IteratorDesc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -685,7 +690,7 @@ func (a *SortedArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.comparator != nil && a.array != nil {
|
||||
@ -706,7 +711,7 @@ func (a *SortedArray) UnmarshalValue(value interface{}) (err error) {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceAny(value)
|
||||
}
|
||||
@ -761,7 +766,7 @@ func (a *SortedArray) FilterEmpty() *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function <f> to every item of array.
|
||||
// Walk applies a user supplied function `f` to every item of array.
|
||||
func (a *SortedArray) Walk(f func(value interface{}) interface{}) *SortedArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -31,14 +31,14 @@ type SortedIntArray struct {
|
||||
}
|
||||
|
||||
// NewSortedIntArray creates and returns an empty sorted array.
|
||||
// The parameter <safe> is 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> is 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
|
||||
@ -46,7 +46,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> is 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{
|
||||
@ -56,8 +56,8 @@ func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedIntArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
// NewSortedIntArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
@ -71,8 +71,8 @@ func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray
|
||||
return NewSortedIntArrayFrom(slice, safe...)
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewSortedIntArrayFrom creates and returns an sorted array with given slice `array`.
|
||||
// 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...)
|
||||
@ -81,8 +81,8 @@ func NewSortedIntArrayFrom(array []int, safe ...bool) *SortedIntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.
|
||||
// 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))
|
||||
@ -90,7 +90,14 @@ func NewSortedIntArrayFromCopy(array []int, safe ...bool) *SortedIntArray {
|
||||
return NewSortedIntArrayFrom(newArray, safe...)
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
// At returns the value by the specified index.
|
||||
// If the given `index` is out of range of the array, it returns `0`.
|
||||
func (a *SortedIntArray) At(index int) (value int) {
|
||||
value, _ = a.Get(index)
|
||||
return
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given `array`.
|
||||
func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -100,7 +107,7 @@ func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort
|
||||
// The parameter `reverse` controls whether sort
|
||||
// in increasing order(default) or decreasing order.
|
||||
func (a *SortedIntArray) Sort() *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
@ -142,7 +149,7 @@ func (a *SortedIntArray) Append(values ...int) *SortedIntArray {
|
||||
}
|
||||
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *SortedIntArray) Get(index int) (value int, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -153,7 +160,7 @@ func (a *SortedIntArray) Get(index int) (value int, found bool) {
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *SortedIntArray) Remove(index int) (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -194,7 +201,7 @@ func (a *SortedIntArray) RemoveValue(value int) bool {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedIntArray) PopLeft() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -207,7 +214,7 @@ func (a *SortedIntArray) PopLeft() (value int, found bool) {
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedIntArray) PopRight() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -221,16 +228,16 @@ func (a *SortedIntArray) PopRight() (value int, found bool) {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedIntArray) PopRand() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRands randomly pops and returns `size` items out of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedIntArray) PopRands(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -247,9 +254,9 @@ func (a *SortedIntArray) PopRands(size int) []int {
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopLefts pops and returns `size` items from the beginning of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedIntArray) PopLefts(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -266,9 +273,9 @@ func (a *SortedIntArray) PopLefts(size int) []int {
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRights pops and returns `size` items from the end of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedIntArray) PopRights(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -290,8 +297,8 @@ func (a *SortedIntArray) PopRights(size int) []int {
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
//
|
||||
// If <end> is negative, then the offset will start from the end of array.
|
||||
// If <end> is omitted, then the sequence will have everything from start up
|
||||
// If `end` is negative, then the offset will start from the end of array.
|
||||
// If `end` is omitted, then the sequence will have everything from start up
|
||||
// until the end of the array.
|
||||
func (a *SortedIntArray) Range(start int, end ...int) []int {
|
||||
a.mu.RLock()
|
||||
@ -317,7 +324,7 @@ func (a *SortedIntArray) Range(start int, end ...int) []int {
|
||||
}
|
||||
|
||||
// SubSlice returns a slice of elements from the array as specified
|
||||
// by the <offset> and <size> parameters.
|
||||
// by the `offset` and `size` parameters.
|
||||
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
|
||||
//
|
||||
// If offset is non-negative, the sequence will start at that offset in the array.
|
||||
@ -416,7 +423,7 @@ func (a *SortedIntArray) Contains(value int) bool {
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// Search searches array by `value`, returns the index of `value`,
|
||||
// or returns -1 if not exists.
|
||||
func (a *SortedIntArray) Search(value int) (index int) {
|
||||
if i, r := a.binSearch(value, true); r == 0 {
|
||||
@ -427,9 +434,9 @@ func (a *SortedIntArray) Search(value int) (index int) {
|
||||
|
||||
// Binary search.
|
||||
// It returns the last compared index and the result.
|
||||
// If <result> equals to 0, it means the value at <index> is equals to <value>.
|
||||
// If <result> lesser than 0, it means the value at <index> is lesser than <value>.
|
||||
// If <result> greater than 0, it means the value at <index> is greater than <value>.
|
||||
// If `result` equals to 0, it means the value at `index` is equals to `value`.
|
||||
// If `result` lesser than 0, it means the value at `index` is lesser than `value`.
|
||||
// If `result` greater than 0, it means the value at `index` is greater than `value`.
|
||||
func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int) {
|
||||
if lock {
|
||||
a.mu.RLock()
|
||||
@ -509,7 +516,7 @@ func (a *SortedIntArray) Clear() *SortedIntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// LockFunc locks writing by callback function <f>.
|
||||
// LockFunc locks writing by callback function `f`.
|
||||
func (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -517,7 +524,7 @@ func (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// RLockFunc locks reading by callback function <f>.
|
||||
// RLockFunc locks reading by callback function `f`.
|
||||
func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -525,8 +532,8 @@ func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Merge merges <array> into current array.
|
||||
// The parameter <array> can be any garray or slice type.
|
||||
// Merge merges `array` into current array.
|
||||
// The parameter `array` can be any garray or slice type.
|
||||
// The difference between Merge and Append is Append supports only specified slice type,
|
||||
// but Merge supports more parameter types.
|
||||
func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray {
|
||||
@ -534,7 +541,7 @@ func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray {
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
// the size of each array is determined by <size>.
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (a *SortedIntArray) Chunk(size int) [][]int {
|
||||
if size < 1 {
|
||||
@ -566,7 +573,7 @@ func (a *SortedIntArray) Rand() (value int, found bool) {
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
// Rands randomly returns `size` items from array(no deleting).
|
||||
func (a *SortedIntArray) Rands(size int) []int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -580,7 +587,7 @@ func (a *SortedIntArray) Rands(size int) []int {
|
||||
return array
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
// Join joins array elements with a string `glue`.
|
||||
func (a *SortedIntArray) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -613,8 +620,8 @@ func (a *SortedIntArray) Iterator(f func(k int, v int) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -625,8 +632,8 @@ func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -658,7 +665,7 @@ func (a *SortedIntArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.array != nil {
|
||||
@ -676,7 +683,7 @@ func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceInt(value)
|
||||
}
|
||||
@ -707,7 +714,7 @@ func (a *SortedIntArray) FilterEmpty() *SortedIntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function <f> to every item of array.
|
||||
// Walk applies a user supplied function `f` to every item of array.
|
||||
func (a *SortedIntArray) Walk(f func(value int) int) *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -32,14 +32,14 @@ type SortedStrArray struct {
|
||||
}
|
||||
|
||||
// NewSortedStrArray creates and returns an empty sorted array.
|
||||
// The parameter <safe> is 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> is 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
|
||||
@ -47,7 +47,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> is 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{
|
||||
@ -57,8 +57,8 @@ func NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedStrArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewSortedStrArrayFrom creates and returns an sorted array with given slice `array`.
|
||||
// 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...)
|
||||
@ -67,8 +67,8 @@ func NewSortedStrArrayFrom(array []string, safe ...bool) *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// NewSortedStrArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// NewSortedStrArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.
|
||||
// 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))
|
||||
@ -76,7 +76,7 @@ func NewSortedStrArrayFromCopy(array []string, safe ...bool) *SortedStrArray {
|
||||
return NewSortedStrArrayFrom(newArray, safe...)
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
// SetArray sets the underlying slice array with the given `array`.
|
||||
func (a *SortedStrArray) SetArray(array []string) *SortedStrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -85,8 +85,15 @@ func (a *SortedStrArray) SetArray(array []string) *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// At returns the value by the specified index.
|
||||
// If the given `index` is out of range of the array, it returns an empty string.
|
||||
func (a *SortedStrArray) At(index int) (value string) {
|
||||
value, _ = a.Get(index)
|
||||
return
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort
|
||||
// The parameter `reverse` controls whether sort
|
||||
// in increasing order(default) or decreasing order.
|
||||
func (a *SortedStrArray) Sort() *SortedStrArray {
|
||||
a.mu.Lock()
|
||||
@ -128,7 +135,7 @@ func (a *SortedStrArray) Append(values ...string) *SortedStrArray {
|
||||
}
|
||||
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *SortedStrArray) Get(index int) (value string, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -139,7 +146,7 @@ func (a *SortedStrArray) Get(index int) (value string, found bool) {
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
// If the given `index` is out of range of the array, the `found` is false.
|
||||
func (a *SortedStrArray) Remove(index int) (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -180,7 +187,7 @@ func (a *SortedStrArray) RemoveValue(value string) bool {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedStrArray) PopLeft() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -193,7 +200,7 @@ func (a *SortedStrArray) PopLeft() (value string, found bool) {
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedStrArray) PopRight() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -207,16 +214,16 @@ func (a *SortedStrArray) PopRight() (value string, found bool) {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedStrArray) PopRand() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRands randomly pops and returns `size` items out of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedStrArray) PopRands(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -233,9 +240,9 @@ func (a *SortedStrArray) PopRands(size int) []string {
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopLefts pops and returns `size` items from the beginning of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedStrArray) PopLefts(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -252,9 +259,9 @@ func (a *SortedStrArray) PopLefts(size int) []string {
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
// PopRights pops and returns `size` items from the end of array.
|
||||
// If the given `size` is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given `size` <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedStrArray) PopRights(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -276,8 +283,8 @@ func (a *SortedStrArray) PopRights(size int) []string {
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
//
|
||||
// If <end> is negative, then the offset will start from the end of array.
|
||||
// If <end> is omitted, then the sequence will have everything from start up
|
||||
// If `end` is negative, then the offset will start from the end of array.
|
||||
// If `end` is omitted, then the sequence will have everything from start up
|
||||
// until the end of the array.
|
||||
func (a *SortedStrArray) Range(start int, end ...int) []string {
|
||||
a.mu.RLock()
|
||||
@ -303,7 +310,7 @@ func (a *SortedStrArray) Range(start int, end ...int) []string {
|
||||
}
|
||||
|
||||
// SubSlice returns a slice of elements from the array as specified
|
||||
// by the <offset> and <size> parameters.
|
||||
// by the `offset` and `size` parameters.
|
||||
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
|
||||
//
|
||||
// If offset is non-negative, the sequence will start at that offset in the array.
|
||||
@ -418,7 +425,7 @@ func (a *SortedStrArray) ContainsI(value string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// Search searches array by `value`, returns the index of `value`,
|
||||
// or returns -1 if not exists.
|
||||
func (a *SortedStrArray) Search(value string) (index int) {
|
||||
if i, r := a.binSearch(value, true); r == 0 {
|
||||
@ -429,9 +436,9 @@ func (a *SortedStrArray) Search(value string) (index int) {
|
||||
|
||||
// Binary search.
|
||||
// It returns the last compared index and the result.
|
||||
// If <result> equals to 0, it means the value at <index> is equals to <value>.
|
||||
// If <result> lesser than 0, it means the value at <index> is lesser than <value>.
|
||||
// If <result> greater than 0, it means the value at <index> is greater than <value>.
|
||||
// If `result` equals to 0, it means the value at `index` is equals to `value`.
|
||||
// If `result` lesser than 0, it means the value at `index` is lesser than `value`.
|
||||
// If `result` greater than 0, it means the value at `index` is greater than `value`.
|
||||
func (a *SortedStrArray) binSearch(value string, lock bool) (index int, result int) {
|
||||
if lock {
|
||||
a.mu.RLock()
|
||||
@ -511,7 +518,7 @@ func (a *SortedStrArray) Clear() *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// LockFunc locks writing by callback function <f>.
|
||||
// LockFunc locks writing by callback function `f`.
|
||||
func (a *SortedStrArray) LockFunc(f func(array []string)) *SortedStrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -519,7 +526,7 @@ func (a *SortedStrArray) LockFunc(f func(array []string)) *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// RLockFunc locks reading by callback function <f>.
|
||||
// RLockFunc locks reading by callback function `f`.
|
||||
func (a *SortedStrArray) RLockFunc(f func(array []string)) *SortedStrArray {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -527,8 +534,8 @@ func (a *SortedStrArray) RLockFunc(f func(array []string)) *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Merge merges <array> into current array.
|
||||
// The parameter <array> can be any garray or slice type.
|
||||
// Merge merges `array` into current array.
|
||||
// The parameter `array` can be any garray or slice type.
|
||||
// The difference between Merge and Append is Append supports only specified slice type,
|
||||
// but Merge supports more parameter types.
|
||||
func (a *SortedStrArray) Merge(array interface{}) *SortedStrArray {
|
||||
@ -536,7 +543,7 @@ func (a *SortedStrArray) Merge(array interface{}) *SortedStrArray {
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
// the size of each array is determined by <size>.
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (a *SortedStrArray) Chunk(size int) [][]string {
|
||||
if size < 1 {
|
||||
@ -568,7 +575,7 @@ func (a *SortedStrArray) Rand() (value string, found bool) {
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
// Rands randomly returns `size` items from array(no deleting).
|
||||
func (a *SortedStrArray) Rands(size int) []string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -582,7 +589,7 @@ func (a *SortedStrArray) Rands(size int) []string {
|
||||
return array
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
// Join joins array elements with a string `glue`.
|
||||
func (a *SortedStrArray) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -615,8 +622,8 @@ func (a *SortedStrArray) Iterator(f func(k int, v string) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -627,8 +634,8 @@ func (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedStrArray) IteratorDesc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@ -671,7 +678,7 @@ func (a *SortedStrArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.array != nil {
|
||||
@ -689,7 +696,7 @@ func (a *SortedStrArray) UnmarshalValue(value interface{}) (err error) {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceStr(value)
|
||||
}
|
||||
@ -720,7 +727,7 @@ func (a *SortedStrArray) FilterEmpty() *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function <f> to every item of array.
|
||||
// Walk applies a user supplied function `f` to every item of array.
|
||||
func (a *SortedStrArray) Walk(f func(value string) string) *SortedStrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
39
container/garray/garray_z_bench_any_test.go
Normal file
39
container/garray/garray_z_bench_any_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type anySortedArrayItem struct {
|
||||
priority int64
|
||||
value interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
anyArray = garray.NewArray()
|
||||
anySortedArray = garray.NewSortedArray(func(a, b interface{}) int {
|
||||
return int(a.(anySortedArrayItem).priority - b.(anySortedArrayItem).priority)
|
||||
})
|
||||
)
|
||||
|
||||
func Benchmark_AnyArray_Add(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
anyArray.Append(i)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_AnySortedArray_Add(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
anySortedArray.Add(anySortedArrayItem{
|
||||
priority: int64(i),
|
||||
value: i,
|
||||
})
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user