mirror of
https://gitee.com/johng/gf
synced 2026-06-08 10:37:44 +08:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a95624ab19 | |||
| 10e042454c | |||
| 2f17d37f7b | |||
| 5c9766fb1b | |||
| 717dae8f5d | |||
| 373dbde42c | |||
| b43e36a79d | |||
| 145fccdf6e | |||
| 5da822fdc4 | |||
| a7d30dd1d5 | |||
| fa96d881e1 | |||
| 7ad66db491 | |||
| 1dbda3872b | |||
| 3619a46f52 | |||
| 6a93d166c5 | |||
| c84e62febe | |||
| 3b0012ec30 | |||
| 62a3f1693d | |||
| ed6796dde0 | |||
| 46721d7552 | |||
| a9a5a78e02 | |||
| 7c4431ceeb | |||
| 8cfdc8f27f | |||
| c6f94ed95a | |||
| 949ac459fc | |||
| 82394cd70e | |||
| bd105a188f | |||
| 09affd3981 | |||
| 8e7e18e22d | |||
| e03fd80fd4 | |||
| adc3201dcf | |||
| 3a681e5b1a | |||
| 285b45d19d | |||
| 783f1c8457 | |||
| daa7f12994 | |||
| 5d464494b6 | |||
| 4ca2513d00 | |||
| 15d69ed950 | |||
| 5c7b25c960 | |||
| 6f5b5e4dc2 | |||
| 007c8a7b64 | |||
| 42214f17fc | |||
| b5f117e932 | |||
| b0f158047c | |||
| 0801245871 | |||
| 278fd3515f | |||
| 56588f3f7f | |||
| a5d01cb547 | |||
| fabf5d1ad5 | |||
| ebae3a4929 | |||
| e4c42bde89 | |||
| f7515edde9 | |||
| 04c422c3af | |||
| 339ca74ff4 | |||
| 741a13379a | |||
| 055c6a668e | |||
| 735c5fc7ed | |||
| 3bfff2347f | |||
| 7d83604540 | |||
| adf2ddb510 | |||
| f30c9020fa | |||
| 1b3073f3f9 | |||
| 615161ac9d | |||
| 02e06e7c6e | |||
| d15268eb22 | |||
| e48415d932 | |||
| e5fa341f39 | |||
| 234d734981 | |||
| d771ed9209 | |||
| 37d72cb8b3 | |||
| 1154f9601b | |||
| 322513f99b | |||
| 6e7ac60d4d | |||
| 405840607f | |||
| 8417e7ef65 | |||
| ac2fe44d8e | |||
| 3030d7f032 | |||
| d74034e08e | |||
| d41cc7c3b6 | |||
| 3120d0bd7a | |||
| 7bebf062be | |||
| 6c657dff37 | |||
| 5896dadaad |
226
README.MD
226
README.MD
@ -40,6 +40,7 @@ golang version >= 1.10
|
||||
|
||||
# Quick Start
|
||||
|
||||
## Hello World
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -56,8 +57,231 @@ func main() {
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Rich Router
|
||||
```go
|
||||
package main
|
||||
|
||||
[View More..](https://goframe.org/start/index)
|
||||
import (
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/{class}-{course}/:name/*act", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Get("class"))
|
||||
r.Response.Writeln(r.Get("course"))
|
||||
r.Response.Writeln(r.Get("name"))
|
||||
r.Response.Writeln(r.Get("act"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Group Routers
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
type Object struct {}
|
||||
|
||||
func (o *Object) Show(r *ghttp.Request) {
|
||||
r.Response.Writeln("Object Show")
|
||||
}
|
||||
|
||||
func (o *Object) Delete(r *ghttp.Request) {
|
||||
r.Response.Writeln("Object REST Delete")
|
||||
}
|
||||
|
||||
func Handler(r *ghttp.Request) {
|
||||
r.Response.Writeln("Handler")
|
||||
}
|
||||
|
||||
func HookHandler(r *ghttp.Request) {
|
||||
r.Response.Writeln("Hook Handler")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
obj := new(Object)
|
||||
group := s.Group("/api")
|
||||
group.ALL ("*", HookHandler, ghttp.HOOK_BEFORE_SERVE)
|
||||
group.ALL ("/handler", Handler)
|
||||
group.ALL ("/obj", obj)
|
||||
group.GET ("/obj/showit", obj, "Show")
|
||||
group.REST("/obj/rest", obj)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
or
|
||||
```go
|
||||
func main() {
|
||||
s := g.Server()
|
||||
obj := new(Object)
|
||||
s.Group("/api").Bind([]ghttp.GroupItem{
|
||||
{"ALL", "*", HookHandler, ghttp.HOOK_BEFORE_SERVE},
|
||||
{"ALL", "/handler", Handler},
|
||||
{"ALL", "/obj", obj},
|
||||
{"GET", "/obj/showit", obj, "Show"},
|
||||
{"REST", "/obj/rest", obj},
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Multi ports & domains
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func Hello1(r *ghttp.Request) {
|
||||
r.Response.Write("127.0.0.1: Hello1!")
|
||||
}
|
||||
|
||||
func Hello2(r *ghttp.Request) {
|
||||
r.Response.Write("localhost: Hello2!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Domain("127.0.0.1").BindHandler("/", Hello1)
|
||||
s.Domain("localhost").BindHandler("/", Hello2)
|
||||
s.SetPort(8100, 8200, 8300)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Template Engine
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/template", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("index.tpl", g.Map{
|
||||
"id": 123,
|
||||
"name": "john",
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## File Uploading
|
||||
```go
|
||||
func Upload(r *ghttp.Request) {
|
||||
if f, h, e := r.FormFile("upload-file"); e == nil {
|
||||
defer f.Close()
|
||||
name := gfile.Basename(h.Filename)
|
||||
buffer := make([]byte, h.Size)
|
||||
f.Read(buffer)
|
||||
gfile.PutBinContents("/tmp/" + name, buffer)
|
||||
r.Response.Write(name + " uploaded successly")
|
||||
} else {
|
||||
r.Response.Write(e.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ORM Operations
|
||||
|
||||
### 1. Retrieving instance
|
||||
```go
|
||||
db := g.DB()
|
||||
db := g.DB("user-center")
|
||||
```
|
||||
### 2. Chaining Operations
|
||||
|
||||
`Where + string`
|
||||
```go
|
||||
// SELECT * FROM user WHERE uid>1 LIMIT 0,10
|
||||
r, err := db.Table("user").Where("uid > ?", 1).Limit(0, 10).Select()
|
||||
|
||||
// SELECT uid,name FROM user WHERE uid>1 LIMIT 0,10
|
||||
r, err := db.Table("user").Fileds("uid,name").Where("uid > ?", 1).Limit(0, 10).Select()
|
||||
|
||||
// SELECT * FROM user WHERE uid=1
|
||||
r, err := db.Table("user").Where("u.uid=1",).One()
|
||||
r, err := db.Table("user").Where("u.uid", 1).One()
|
||||
r, err := db.Table("user").Where("u.uid=?", 1).One()
|
||||
// SELECT * FROM user WHERE (uid=1) AND (name='john')
|
||||
r, err := db.Table("user").Where("uid", 1).Where("name", "john").One()
|
||||
r, err := db.Table("user").Where("uid=?", 1).And("name=?", "john").One()
|
||||
// SELECT * FROM user WHERE (uid=1) OR (name='john')
|
||||
r, err := db.Table("user").Where("uid=?", 1).Or("name=?", "john").One()
|
||||
```
|
||||
`Where + map`
|
||||
```go
|
||||
// SELECT * FROM user WHERE uid=1 AND name='john'
|
||||
r, err := db.Table("user").Where(g.Map{"uid" : 1, "name" : "john"}).One()
|
||||
// SELECT * FROM user WHERE uid=1 AND age>18
|
||||
r, err := db.Table("user").Where(g.Map{"uid" : 1, "age>" : 18}).One()
|
||||
```
|
||||
`Where + struct/*struct`
|
||||
```go
|
||||
type User struct {
|
||||
Id int `json:"uid"`
|
||||
UserName string `gconv:"name"`
|
||||
}
|
||||
// SELECT * FROM user WHERE uid =1 AND name='john'
|
||||
r, err := db.Table("user").Where(User{ Id : 1, UserName : "john"}).One()
|
||||
// SELECT * FROM user WHERE uid =1
|
||||
r, err := db.Table("user").Where(&User{ Id : 1}).One()
|
||||
```
|
||||
### 3. Update & Delete
|
||||
```go
|
||||
// UPDATE user SET name='john guo' WHERE name='john'
|
||||
r, err := db.Table("user").Data(gdb.Map{"name" : "john guo"}).Where("name=?", "john").Update()
|
||||
r, err := db.Table("user").Data("name='john guo'").Where("name=?", "john").Update()
|
||||
// UPDATE user SET status=1 ORDER BY login_time asc LIMIT 10
|
||||
r, err := db.Table("user").Data("status", 1).OrderBy("login_time asc").Limit(10).Update
|
||||
|
||||
// DELETE FROM user WHERE uid=10
|
||||
r, err := db.Table("user").Where("uid=?", 10).Delete()
|
||||
// DELETE FROM user ORDER BY login_time asc LIMIT 10
|
||||
r, err := db.Table("user").OrderBy("login_time asc").Limit(10).Delete()
|
||||
```
|
||||
### 4. Insert & Replace & Save
|
||||
```go
|
||||
r, err := db.Table("user").Data(g.Map{"name": "john"}).Insert()
|
||||
r, err := db.Table("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()
|
||||
r, err := db.Table("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()
|
||||
```
|
||||
### 5. Transaction
|
||||
```go
|
||||
if tx, err := db.Begin(); err == nil {
|
||||
r, err := tx.Save("user", g.Map{
|
||||
"uid" : 1,
|
||||
"name" : "john",
|
||||
})
|
||||
tx.Commit()
|
||||
}
|
||||
```
|
||||
### 6. Error Handling
|
||||
```go
|
||||
func GetOrderInfo(id int) (order *Order, err error) {
|
||||
err = g.DB().Table("order").Where("id", id).Struct(&order)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
[More Features...](https://goframe.org/start/index)
|
||||
|
||||
|
||||
# License
|
||||
|
||||
@ -31,6 +31,7 @@ func Test_SortedIntArray1(t *testing.T) {
|
||||
array.Add(i)
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.Add().Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedIntArray2(t *testing.T) {
|
||||
@ -44,11 +45,15 @@ func Test_SortedIntArray2(t *testing.T) {
|
||||
|
||||
func Test_SortedStringArray1(t *testing.T) {
|
||||
expect := []string{"0", "1", "10", "2", "3", "4", "5", "6", "7", "8", "9"}
|
||||
array := garray.NewSortedStringArray()
|
||||
array1 := garray.NewSortedStringArray()
|
||||
array2 := garray.NewSortedStringArray(true)
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(gconv.String(i))
|
||||
array1.Add(gconv.String(i))
|
||||
array2.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array1.Slice(), expect)
|
||||
gtest.Assert(array2.Slice(), expect)
|
||||
|
||||
}
|
||||
|
||||
func Test_SortedStringArray2(t *testing.T) {
|
||||
@ -58,6 +63,8 @@ func Test_SortedStringArray2(t *testing.T) {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Add()
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedArray1(t *testing.T) {
|
||||
@ -73,13 +80,18 @@ func Test_SortedArray1(t *testing.T) {
|
||||
|
||||
func Test_SortedArray2(t *testing.T) {
|
||||
expect := []string{"0", "1", "10", "2", "3", "4", "5", "6", "7", "8", "9"}
|
||||
array := garray.NewSortedArray(func(v1, v2 interface{}) int {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
})
|
||||
}
|
||||
array := garray.NewSortedArray(func1)
|
||||
array2 := garray.NewSortedArray(func1, true)
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(gconv.String(i))
|
||||
array2.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.Add().Slice(), expect)
|
||||
gtest.Assert(array2.Slice(), expect)
|
||||
}
|
||||
|
||||
func TestNewFromCopy(t *testing.T) {
|
||||
@ -89,6 +101,5 @@ func TestNewFromCopy(t *testing.T) {
|
||||
gtest.AssertIN(array1.PopRands(2), a1)
|
||||
gtest.Assert(len(array1.PopRands(1)), 1)
|
||||
gtest.Assert(len(array1.PopRands(9)), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,7 +9,9 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
@ -18,12 +20,15 @@ import (
|
||||
func Test_IntArray_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{0, 1, 2, 3}
|
||||
expect2 := []int{}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
array2 := garray.NewIntArrayFrom(expect2)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array2.Search(100), -1)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
@ -44,13 +49,16 @@ func TestIntArray_Sort(t *testing.T) {
|
||||
expect1 := []int{0, 1, 2, 3}
|
||||
expect2 := []int{3, 2, 1, 0}
|
||||
array := garray.NewIntArray()
|
||||
array2 := garray.NewIntArray(true)
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
array2.Append(i)
|
||||
}
|
||||
array.Sort()
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.Sort(true)
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
gtest.Assert(array2.Slice(), expect2)
|
||||
})
|
||||
}
|
||||
|
||||
@ -98,21 +106,48 @@ func TestIntArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(value1)
|
||||
array2 := garray.NewIntArrayFrom(value1, true)
|
||||
gtest.Assert(array1.Range(0, 1), []int{0})
|
||||
gtest.Assert(array1.Range(1, 2), []int{1})
|
||||
gtest.Assert(array1.Range(0, 2), []int{0, 1})
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
gtest.Assert(array2.Range(1, 2), []int{1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
a2 := []int{4, 5, 6, 7}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []int{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
n1 := []int{0, 1, 2, 3}
|
||||
n2 := []int{4, 5, 6, 7}
|
||||
i1 := []interface{}{"1", "2"}
|
||||
s1 := []string{"a", "b", "c"}
|
||||
s2 := []string{"e", "f"}
|
||||
a1 := garray.NewIntArrayFrom(n1)
|
||||
a2 := garray.NewIntArrayFrom(n2)
|
||||
a3 := garray.NewArrayFrom(i1)
|
||||
a4 := garray.NewStringArrayFrom(s1)
|
||||
|
||||
a5 := garray.NewSortedStringArrayFrom(s2)
|
||||
a6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
|
||||
a7 := garray.NewSortedStringArrayFrom(s1)
|
||||
a8 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
|
||||
gtest.Assert(a1.Merge(a2).Slice(), []int{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
gtest.Assert(a1.Merge(a3).Len(), 10)
|
||||
gtest.Assert(a1.Merge(a4).Len(), 13)
|
||||
gtest.Assert(a1.Merge(a5).Len(), 15)
|
||||
gtest.Assert(a1.Merge(a6).Len(), 18)
|
||||
gtest.Assert(a1.Merge(a7).Len(), 21)
|
||||
gtest.Assert(a1.Merge(a8).Len(), 23)
|
||||
})
|
||||
}
|
||||
|
||||
@ -124,6 +159,7 @@ func TestIntArray_Fill(t *testing.T) {
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []int{0, 100, 100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []int{100, 100})
|
||||
gtest.Assert(array2.Fill(-1, 2, 100).Slice(), []int{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
@ -136,6 +172,7 @@ func TestIntArray_Chunk(t *testing.T) {
|
||||
gtest.Assert(chunks[0], []int{1, 2})
|
||||
gtest.Assert(chunks[1], []int{3, 4})
|
||||
gtest.Assert(chunks[2], []int{5})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -153,6 +190,7 @@ func TestIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a1, true)
|
||||
gtest.Assert(array1.SubSlice(6), []int{6})
|
||||
gtest.Assert(array1.SubSlice(5), []int{5, 6})
|
||||
gtest.Assert(array1.SubSlice(8), nil)
|
||||
@ -168,6 +206,7 @@ func TestIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Assert(array1.SubSlice(-9, 3), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -1), []int{0})
|
||||
gtest.Assert(array1.SubSlice(1, -3), nil)
|
||||
gtest.Assert(array2.SubSlice(0, 2), []int{0, 1})
|
||||
})
|
||||
}
|
||||
|
||||
@ -193,7 +232,6 @@ func TestIntArray_PopRands(t *testing.T) {
|
||||
ns2 := array.PopRands(7)
|
||||
gtest.AssertIN(len(ns2), 6)
|
||||
gtest.AssertIN(ns2, []int{100, 200, 300, 400, 500, 600})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -226,6 +264,7 @@ func TestNewSortedIntArrayFrom(t *testing.T) {
|
||||
a1 := []int{0, 3, 2, 1, 4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
gtest.Assert(array1.Slice(), a1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -260,7 +299,6 @@ func TestSortedIntArray_Sort(t *testing.T) {
|
||||
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []int{0, 1, 2, 3})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -271,7 +309,6 @@ func TestSortedIntArray_Get(t *testing.T) {
|
||||
gtest.Assert(array1.Get(0), 0)
|
||||
gtest.Assert(array1.Get(1), 1)
|
||||
gtest.Assert(array1.Get(3), 5)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -296,7 +333,6 @@ func TestSortedIntArray_Remove(t *testing.T) {
|
||||
i3 = array2.Remove(1)
|
||||
gtest.Assert(array2.Search(4), -1)
|
||||
gtest.Assert(i3, 4)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -308,7 +344,6 @@ func TestSortedIntArray_PopLeft(t *testing.T) {
|
||||
gtest.Assert(i1, 1)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(1), -1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -348,7 +383,6 @@ func TestSortedIntArray_PopRands(t *testing.T) {
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.Assert(len(ns2), 4)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -365,7 +399,6 @@ func TestSortedIntArray_PopLefts(t *testing.T) {
|
||||
ns2 := array2.PopLefts(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -389,6 +422,7 @@ func TestSortedIntArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2, 6, 7}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
ns1 := array1.Range(1, 4)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1, []int{2, 3, 5})
|
||||
@ -401,7 +435,7 @@ func TestSortedIntArray_Range(t *testing.T) {
|
||||
|
||||
nsl := array1.Range(5, 8)
|
||||
gtest.Assert(len(nsl), 1)
|
||||
|
||||
gtest.Assert(array2.Range(1, 2), []int{2})
|
||||
})
|
||||
}
|
||||
|
||||
@ -418,7 +452,6 @@ func TestSortedIntArray_Contains(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
//gtest.Assert(array1.Contains(3),true) //todo 这一行应该返回true
|
||||
gtest.Assert(array1.Contains(4), false)
|
||||
})
|
||||
}
|
||||
@ -439,7 +472,6 @@ func TestSortedIntArray_Clear(t *testing.T) {
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -453,7 +485,6 @@ func TestSortedIntArray_Chunk(t *testing.T) {
|
||||
gtest.Assert(ns1[0], []int{1, 2})
|
||||
gtest.Assert(ns1[2], []int{5})
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -461,6 +492,7 @@ func TestSortedIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
ns1 := array1.SubSlice(1, 2)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
gtest.Assert(ns1, []int{2, 3})
|
||||
@ -475,6 +507,10 @@ func TestSortedIntArray_SubSlice(t *testing.T) {
|
||||
ns4 := array1.SubSlice(3, 1)
|
||||
gtest.Assert(len(ns4), 1)
|
||||
gtest.Assert(ns4, []int{4})
|
||||
gtest.Assert(array1.SubSlice(-1, 1), []int{5})
|
||||
gtest.Assert(array1.SubSlice(-9, 1), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -9), nil)
|
||||
gtest.Assert(array2.SubSlice(1, 2), []int{2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
@ -519,7 +555,6 @@ func TestSortedIntArray_SetUnique(t *testing.T) {
|
||||
array1.SetUnique(true)
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(array1, []int{1, 2, 3, 4, 5})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -531,7 +566,6 @@ func TestIntArray_SetArray(t *testing.T) {
|
||||
array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(array1, []int{6, 7})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -621,3 +655,171 @@ func TestIntArray_Remove(t *testing.T) {
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewIntArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []int) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_SortFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 4, 3, 2}
|
||||
a1 := garray.NewIntArrayFrom(s1)
|
||||
func1 := func(v1, v2 int) bool {
|
||||
return v1 < v2
|
||||
}
|
||||
a11 := a1.SortFunc(func1)
|
||||
gtest.Assert(a11, []int{1, 2, 3, 4})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewIntArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []int) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1)
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []int) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []int) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
i0 := []int{1, 2, 3, 4}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStringArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStringArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewSortedIntArrayFrom(i0)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
@ -14,28 +14,36 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_Array_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
array2 := garray.NewArrayFrom(expect)
|
||||
array3 := garray.NewArrayFrom([]interface{}{})
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array3.Search(100), -1)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
|
||||
gtest.Assert(array2.Remove(3), 3)
|
||||
gtest.Assert(array2.Remove(1), 1)
|
||||
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 1, 2, 3, 4})
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 1, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
}
|
||||
@ -111,20 +119,48 @@ func TestArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value1, true)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{0})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{1})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
gtest.Assert(array2.Range(1, 3), []interface{}{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
a2 := []interface{}{4, 5, 6, 7}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
i1 := []interface{}{0, 1, 2, 3}
|
||||
i2 := []interface{}{4, 5, 6, 7}
|
||||
array1 := garray.NewArrayFrom(i1)
|
||||
array2 := garray.NewArrayFrom(i2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []interface{}{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
|
||||
//s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i3 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i4 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStringArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStringArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewArrayFrom(i1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i3).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i4).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
@ -133,9 +169,10 @@ func TestArray_Fill(t *testing.T) {
|
||||
a1 := []interface{}{0}
|
||||
a2 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
array2 := garray.NewArrayFrom(a2, true)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []interface{}{0, 100, 100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []interface{}{100, 100})
|
||||
gtest.Assert(array2.Fill(-1, 2, 100).Slice(), []interface{}{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
@ -148,6 +185,7 @@ func TestArray_Chunk(t *testing.T) {
|
||||
gtest.Assert(chunks[0], []interface{}{1, 2})
|
||||
gtest.Assert(chunks[1], []interface{}{3, 4})
|
||||
gtest.Assert(chunks[2], []interface{}{5})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -165,9 +203,15 @@ func TestArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a1, true)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []interface{}{2, 3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []interface{}{5, 6})
|
||||
gtest.Assert(array1.SubSlice(9, 1), nil)
|
||||
gtest.Assert(array1.SubSlice(-2, 2), []interface{}{5, 6})
|
||||
gtest.Assert(array1.SubSlice(-9, 2), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -2), nil)
|
||||
gtest.Assert(array2.SubSlice(0, 2), []interface{}{0, 1})
|
||||
})
|
||||
}
|
||||
|
||||
@ -179,6 +223,14 @@ func TestArray_Rand(t *testing.T) {
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
i1 := a1.Rand()
|
||||
gtest.Assert(a1.Contains(i1), true)
|
||||
gtest.Assert(a1.Len(), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Shuffle(t *testing.T) {
|
||||
@ -496,6 +548,7 @@ func TestSortedArray_Range(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array2 := garray.NewSortedArrayFrom(a1, func1, true)
|
||||
i1 := array1.Range(2, 5)
|
||||
gtest.Assert(i1, []interface{}{"c", "d", "e"})
|
||||
gtest.Assert(array1.Len(), 6)
|
||||
@ -509,6 +562,8 @@ func TestSortedArray_Range(t *testing.T) {
|
||||
gtest.Assert(len(i2), 2)
|
||||
gtest.Assert(i2, []interface{}{"e", "f"})
|
||||
|
||||
gtest.Assert(array2.Range(1, 3), []interface{}{"b", "c"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -587,6 +642,7 @@ func TestSortedArray_SubSlice(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array2 := garray.NewSortedArrayFrom(a1, func1, true)
|
||||
i1 := array1.SubSlice(2, 3)
|
||||
gtest.Assert(len(i1), 3)
|
||||
gtest.Assert(i1, []interface{}{"c", "d", "e"})
|
||||
@ -598,6 +654,13 @@ func TestSortedArray_SubSlice(t *testing.T) {
|
||||
i1 = array1.SubSlice(7, 2)
|
||||
gtest.Assert(len(i1), 0)
|
||||
|
||||
s1 := array1.SubSlice(1, -2)
|
||||
gtest.Assert(s1, nil)
|
||||
|
||||
s1 = array1.SubSlice(-9, 2)
|
||||
gtest.Assert(s1, nil)
|
||||
gtest.Assert(array2.SubSlice(1, 3), []interface{}{"b", "c", "d"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -676,3 +739,168 @@ func TestSortedArray_SetUnique(t *testing.T) {
|
||||
gtest.Assert(array1, []interface{}{"a", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedArrayFrom(s1, func1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []interface{}) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedArrayFrom(s1, func1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []interface{}) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候不会被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStringArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStringArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
|
||||
a1 := garray.NewSortedArrayFrom(s1, func1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []interface{}) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []interface{}) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -14,12 +14,15 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_StringArray_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"0", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
array2 := garray.NewStringArrayFrom(expect, true)
|
||||
array3 := garray.NewStringArrayFrom([]string{})
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, "100")
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
@ -37,6 +40,8 @@ func Test_StringArray_Basic(t *testing.T) {
|
||||
array.InsertAfter(6, "400")
|
||||
gtest.Assert(array.Slice(), []string{"100", "200", "1", "2", "3", "300", "4", "400"})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
gtest.Assert(array2.Slice(), expect)
|
||||
gtest.Assert(array3.Search("100"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -99,20 +104,48 @@ func TestString_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(value1)
|
||||
array2 := garray.NewStringArrayFrom(value1, true)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{"0"})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{"1"})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{"0", "1"})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
gtest.Assert(array1.Range(10, 1), nil)
|
||||
gtest.Assert(array2.Range(0, 1), []interface{}{"0"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3"}
|
||||
a2 := []string{"4", "5", "6", "7"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a2)
|
||||
a11 := []string{"0", "1", "2", "3"}
|
||||
a21 := []string{"4", "5", "6", "7"}
|
||||
array1 := garray.NewStringArrayFrom(a11)
|
||||
array2 := garray.NewStringArrayFrom(a21)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []string{"0", "1", "2", "3", "4", "5", "6", "7"})
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStringArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStringArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewStringArrayFrom(s1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
@ -139,7 +172,6 @@ func TestStringArray_Chunk(t *testing.T) {
|
||||
gtest.Assert(chunks[1], []string{"3", "4"})
|
||||
gtest.Assert(chunks[2], []string{"5"})
|
||||
gtest.Assert(len(array1.Chunk(0)), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -157,9 +189,15 @@ func TestStringArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a1, true)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []string{"0", "1"})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []string{"2", "3"})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []string{"5", "6"})
|
||||
gtest.Assert(array1.SubSlice(8, 2), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -2), nil)
|
||||
gtest.Assert(array1.SubSlice(-5, 2), []string{"2", "3"})
|
||||
gtest.Assert(array1.SubSlice(-10, 1), nil)
|
||||
gtest.Assert(array2.SubSlice(0, 2), []string{"0", "1"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -172,7 +210,6 @@ func TestStringArray_Rand(t *testing.T) {
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
gtest.Assert(len(array1.Rand()), 1)
|
||||
gtest.AssertIN(array1.Rand(), a1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -181,10 +218,9 @@ func TestStringArray_PopRands(t *testing.T) {
|
||||
a1 := []string{"a", "b", "c", "d", "e", "f", "g"}
|
||||
a2 := []string{"1", "2", "3", "4", "5", "6", "7"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
//todo gtest.AssertIN(array1.PopRands(1),a1)
|
||||
gtest.AssertIN(array1.PopRands(1), strings.Join(a1, ","))
|
||||
gtest.AssertNI(array1.PopRands(1), strings.Join(a2, ","))
|
||||
|
||||
gtest.Assert(len(array1.PopRands(10)), 5)
|
||||
})
|
||||
}
|
||||
|
||||
@ -275,26 +311,6 @@ func TestStringArray_Sum(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
//func TestStringArray_SortFunc(t *testing.T) {
|
||||
// gtest.Case(t, func() {
|
||||
// a1 := []string{"0","1","2","3","4","5","6"}
|
||||
// //a2 := []string{"0","a","3","4","5","6"}
|
||||
// array1 := garray.NewStringArrayFrom(a1)
|
||||
//
|
||||
// lesss:=func(v1,v2 string)bool{
|
||||
// if v1>v2{
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
// gtest.Assert(array1.Len(),7)
|
||||
// gtest.Assert(lesss("1","2"),false)
|
||||
// gtest.Assert(array1.SortFunc(lesss("1","2")) ,false)
|
||||
//
|
||||
//
|
||||
// })
|
||||
//}
|
||||
|
||||
func TestStringArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
@ -324,7 +340,6 @@ func TestStringArray_CountValues(t *testing.T) {
|
||||
gtest.Assert(len(m1), 6)
|
||||
gtest.Assert(m1["2"], 1)
|
||||
gtest.Assert(m1["4"], 2)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -357,7 +372,6 @@ func TestSortedStringArray_SetArray(t *testing.T) {
|
||||
gtest.Assert(array1.Contains("d"), false)
|
||||
gtest.Assert(array1.Contains("b"), false)
|
||||
gtest.Assert(array1.Contains("g"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -367,7 +381,7 @@ func TestSortedStringArray_Sort(t *testing.T) {
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
array1.Sort() //todo 这个SortedStringArray.sort这个方法没有必要,
|
||||
array1.Sort()
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("c"), true)
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
@ -380,7 +394,6 @@ func TestSortedStringArray_Get(t *testing.T) {
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(2), "c")
|
||||
gtest.Assert(array1.Get(0), "a")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -400,7 +413,6 @@ func TestSortedStringArray_Remove(t *testing.T) {
|
||||
// 此时array1里的元素只剩下2个
|
||||
gtest.Assert(array1.Remove(1), "d")
|
||||
gtest.Assert(array1.Len(), 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -486,6 +498,7 @@ func TestSortedStringArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array2 := garray.NewSortedStringArrayFrom(a1, true)
|
||||
s1 := array1.Range(2, 4)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"c", "d"})
|
||||
@ -497,6 +510,11 @@ func TestSortedStringArray_Range(t *testing.T) {
|
||||
s1 = array1.Range(4, 8)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"e", "f", "g"})
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
|
||||
s2 := array2.Range(2, 4)
|
||||
gtest.Assert(s2, []string{"c", "d"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -528,7 +546,6 @@ func TestSortedStringArray_Clear(t *testing.T) {
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -536,6 +553,7 @@ func TestSortedStringArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array2 := garray.NewSortedStringArrayFrom(a1, true)
|
||||
s1 := array1.SubSlice(1, 3)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"b", "c", "d"})
|
||||
@ -547,6 +565,16 @@ func TestSortedStringArray_SubSlice(t *testing.T) {
|
||||
s3 := array1.SubSlice(10, 2)
|
||||
gtest.Assert(len(s3), 0)
|
||||
|
||||
s3 = array1.SubSlice(-5, 2)
|
||||
gtest.Assert(s3, []string{"c", "d"})
|
||||
|
||||
s3 = array1.SubSlice(-10, 2)
|
||||
gtest.Assert(s3, nil)
|
||||
|
||||
s3 = array1.SubSlice(1, -2)
|
||||
gtest.Assert(s3, nil)
|
||||
|
||||
gtest.Assert(array2.SubSlice(1, 3), []string{"b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -564,7 +592,6 @@ func TestSortedStringArray_Rand(t *testing.T) {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.AssertIN(array1.Rand(), []string{"e", "a", "d"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -611,6 +638,7 @@ func TestSortedStringArray_Chunk(t *testing.T) {
|
||||
gtest.Assert(len(array2), 3)
|
||||
gtest.Assert(len(array2[0]), 2)
|
||||
gtest.Assert(array2[1], []string{"c", "d"})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -634,6 +662,174 @@ func TestStringArray_Remove(t *testing.T) {
|
||||
s1 = array1.Remove(3)
|
||||
gtest.Assert(s1, "c")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewStringArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []string) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStringArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []string) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStringArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []string) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStringArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStringArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewSortedStringArrayFrom(s1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_SortFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "d", "c", "b"}
|
||||
a1 := garray.NewStringArrayFrom(s1)
|
||||
func1 := func(v1, v2 string) bool {
|
||||
return v1 < v2
|
||||
}
|
||||
a11 := a1.SortFunc(func1)
|
||||
gtest.Assert(a11, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewStringArrayFrom(s1)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []string) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
// Copyright 2019 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 gpool_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gogf/gf/g"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -30,7 +37,7 @@ func Test_Gpool(t *testing.T) {
|
||||
//test won't be timeout
|
||||
v1, err1 := p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, 1)
|
||||
gtest.AssertIN(v1, g.Slice{1, 2})
|
||||
//test clear
|
||||
p1.Clear()
|
||||
gtest.Assert(p1.Size(), 0)
|
||||
@ -43,13 +50,12 @@ func Test_Gpool(t *testing.T) {
|
||||
p1.Put(4)
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, 3)
|
||||
gtest.AssertIN(v1, g.Slice{3, 4})
|
||||
//test close
|
||||
p1.Close()
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, "hello")
|
||||
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
|
||||
@ -58,33 +58,6 @@ func (v *Var) Interface() interface{} {
|
||||
return v.Val()
|
||||
}
|
||||
|
||||
// Time converts and returns <v> as time.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) Time(format ...string) time.Time {
|
||||
return gconv.Time(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Duration converts and returns <v> as time.Duration.
|
||||
// If value of <v> is string, then it uses time.ParseDuration for conversion.
|
||||
func (v *Var) Duration() time.Duration {
|
||||
return gconv.Duration(v.Val())
|
||||
}
|
||||
|
||||
// GTime converts and returns <v> as *gtime.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) GTime(format ...string) *gtime.Time {
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <objPointer>.
|
||||
// The parameter <objPointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// IsNil checks whether <v> is nil.
|
||||
func (v *Var) IsNil() bool {
|
||||
return v.Val() == nil
|
||||
@ -184,3 +157,57 @@ func (v *Var) Strings() []string {
|
||||
func (v *Var) Interfaces() []interface{} {
|
||||
return gconv.Interfaces(v.Val())
|
||||
}
|
||||
|
||||
// Time converts and returns <v> as time.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) Time(format ...string) time.Time {
|
||||
return gconv.Time(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Duration converts and returns <v> as time.Duration.
|
||||
// If value of <v> is string, then it uses time.ParseDuration for conversion.
|
||||
func (v *Var) Duration() time.Duration {
|
||||
return gconv.Duration(v.Val())
|
||||
}
|
||||
|
||||
// GTime converts and returns <v> as *gtime.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) GTime(format ...string) *gtime.Time {
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Map converts <v> to map[string]interface{}.
|
||||
func (v *Var) Map(tags ...string) map[string]interface{} {
|
||||
return gconv.Map(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// MapDeep converts <v> to map[string]interface{} recursively.
|
||||
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
|
||||
return gconv.MapDeep(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <pointer>.
|
||||
// The parameter <pointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <pointer> recursively.
|
||||
// The parameter <pointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) StructDeep(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.StructDeep(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// Structs converts <v> to given struct slice.
|
||||
func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return gconv.Structs(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// StructsDeep converts <v> to given struct slice recursively.
|
||||
func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return gconv.StructsDeep(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
@ -8,20 +8,21 @@ package gdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
// 同步数据库表结构到内存中
|
||||
func (bs *dbBase) syncTableStructure() {
|
||||
bs.tables = make(map[string]map[string]string)
|
||||
for _, table := range bs.db.getTables() {
|
||||
bs.tables[table], _ = bs.db.getTableFields(table)
|
||||
}
|
||||
}
|
||||
*/
|
||||
//// 同步数据库表结构到内存中
|
||||
//func (bs *dbBase) syncTableStructure() {
|
||||
// bs.tables = make(map[string]map[string]string)
|
||||
// for _, table := range bs.db.getTables() {
|
||||
// bs.tables[table], _ = bs.db.getTableFields(table)
|
||||
// }
|
||||
//}
|
||||
|
||||
// 字段类型转换,将数据库字段类型转换为golang变量类型
|
||||
func (bs *dbBase) convertValue(fieldValue interface{}, fieldType string) interface{} {
|
||||
@ -31,7 +32,7 @@ func (bs *dbBase) convertValue(fieldValue interface{}, fieldType string) interfa
|
||||
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
|
||||
return gconv.Bytes(fieldValue)
|
||||
|
||||
case "bit", "int", "tinyint", "small_int", "medium_int":
|
||||
case "int", "tinyint", "small_int", "medium_int":
|
||||
return gconv.Int(fieldValue)
|
||||
|
||||
case "big_int":
|
||||
@ -40,6 +41,20 @@ func (bs *dbBase) convertValue(fieldValue interface{}, fieldType string) interfa
|
||||
case "float", "double", "decimal":
|
||||
return gconv.Float64(fieldValue)
|
||||
|
||||
case "bit":
|
||||
s := gconv.String(fieldValue)
|
||||
// 这里的字符串判断是为兼容不同的数据库类型,如: mssql
|
||||
if strings.EqualFold(s, "true") {
|
||||
return 1
|
||||
}
|
||||
if strings.EqualFold(s, "false") {
|
||||
return 0
|
||||
}
|
||||
if b, ok := fieldValue.([]byte); ok {
|
||||
return gbinary.BeDecodeToInt64(b)
|
||||
}
|
||||
return gconv.Int(fieldValue)
|
||||
|
||||
case "bool":
|
||||
return gconv.Bool(fieldValue)
|
||||
|
||||
|
||||
@ -652,6 +652,21 @@ func TestModel_Where(t *testing.T) {
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// slice
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Where("id=? AND nickname=?", g.Slice{3, "T3"}...).One()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Where("passport like ? and nickname like ?", g.Slice{"t3", "T3"}...).One()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Where(g.Map{"id": 3, "nickname": "T3"}).One()
|
||||
|
||||
@ -22,10 +22,7 @@ func Encode(src []byte) []byte {
|
||||
func Decode(dst []byte) ([]byte, error) {
|
||||
src := make([]byte, base64.StdEncoding.DecodedLen(len(dst)))
|
||||
n, err := base64.StdEncoding.Decode(src, dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return src[:n], nil
|
||||
return src[:n], err
|
||||
}
|
||||
|
||||
// EncodeString encodes bytes with BASE64 algorithm.
|
||||
|
||||
@ -6,340 +6,129 @@
|
||||
|
||||
// Package gbinary provides useful API for handling binary/bytes data.
|
||||
//
|
||||
// 注意gbinary模块统一使用LittleEndian进行编码。
|
||||
// 注意gbinary模块默认使用LittleEndian进行编码。
|
||||
package gbinary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// 二进制位(0|1)
|
||||
type Bit int8
|
||||
|
||||
// 针对基本类型进行二进制打包,支持的基本数据类型包括:int/8/16/32/64、uint/8/16/32/64、float32/64、bool、string、[]byte
|
||||
// 其他未知类型使用 fmt.Sprintf("%v", value) 转换为字符串之后处理
|
||||
func Encode(vs ...interface{}) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
for i := 0; i < len(vs); i++ {
|
||||
if vs[i] == nil {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
switch value := vs[i].(type) {
|
||||
case int:
|
||||
buf.Write(EncodeInt(value))
|
||||
case int8:
|
||||
buf.Write(EncodeInt8(value))
|
||||
case int16:
|
||||
buf.Write(EncodeInt16(value))
|
||||
case int32:
|
||||
buf.Write(EncodeInt32(value))
|
||||
case int64:
|
||||
buf.Write(EncodeInt64(value))
|
||||
case uint:
|
||||
buf.Write(EncodeUint(value))
|
||||
case uint8:
|
||||
buf.Write(EncodeUint8(value))
|
||||
case uint16:
|
||||
buf.Write(EncodeUint16(value))
|
||||
case uint32:
|
||||
buf.Write(EncodeUint32(value))
|
||||
case uint64:
|
||||
buf.Write(EncodeUint64(value))
|
||||
case bool:
|
||||
buf.Write(EncodeBool(value))
|
||||
case string:
|
||||
buf.Write(EncodeString(value))
|
||||
case []byte:
|
||||
buf.Write(value)
|
||||
case float32:
|
||||
buf.Write(EncodeFloat32(value))
|
||||
case float64:
|
||||
buf.Write(EncodeFloat64(value))
|
||||
default:
|
||||
if err := binary.Write(buf, binary.LittleEndian, value); err != nil {
|
||||
buf.Write(EncodeString(fmt.Sprintf("%v", value)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
func Encode(values ...interface{}) []byte {
|
||||
return LeEncode(values...)
|
||||
}
|
||||
|
||||
// 将变量转换为二进制[]byte,并指定固定的[]byte长度返回,长度单位为字节(byte);
|
||||
// 如果转换的二进制长度超过指定长度,那么进行截断处理
|
||||
func EncodeByLength(length int, vs ...interface{}) []byte {
|
||||
b := Encode(vs...)
|
||||
if len(b) < length {
|
||||
b = append(b, make([]byte, length-len(b))...)
|
||||
} else if len(b) > length {
|
||||
b = b[0:length]
|
||||
}
|
||||
return b
|
||||
func EncodeByLength(length int, values ...interface{}) []byte {
|
||||
return LeEncodeByLength(length, values...)
|
||||
}
|
||||
|
||||
// 整形二进制解包,注意第二个及其后参数为字长确定的整形变量的指针地址,以便确定解析的[]byte长度,
|
||||
// 例如:int8/16/32/64、uint8/16/32/64、float32/64等等
|
||||
func Decode(b []byte, vs ...interface{}) error {
|
||||
buf := bytes.NewBuffer(b)
|
||||
for i := 0; i < len(vs); i++ {
|
||||
err := binary.Read(buf, binary.LittleEndian, vs[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func Decode(b []byte, values ...interface{}) error {
|
||||
return LeDecode(b, values...)
|
||||
}
|
||||
|
||||
func EncodeString(s string) []byte {
|
||||
return []byte(s)
|
||||
return LeEncodeString(s)
|
||||
}
|
||||
|
||||
func DecodeToString(b []byte) string {
|
||||
return string(b)
|
||||
return LeDecodeToString(b)
|
||||
}
|
||||
|
||||
func EncodeBool(b bool) []byte {
|
||||
if b == true {
|
||||
return []byte{1}
|
||||
} else {
|
||||
return []byte{0}
|
||||
}
|
||||
return LeEncodeBool(b)
|
||||
}
|
||||
|
||||
// 自动识别int类型长度,转换为[]byte
|
||||
func EncodeInt(i int) []byte {
|
||||
if i <= math.MaxInt8 {
|
||||
return EncodeInt8(int8(i))
|
||||
} else if i <= math.MaxInt16 {
|
||||
return EncodeInt16(int16(i))
|
||||
} else if i <= math.MaxInt32 {
|
||||
return EncodeInt32(int32(i))
|
||||
} else {
|
||||
return EncodeInt64(int64(i))
|
||||
}
|
||||
return LeEncodeInt(i)
|
||||
}
|
||||
|
||||
// 自动识别uint类型长度,转换为[]byte
|
||||
func EncodeUint(i uint) []byte {
|
||||
if i <= math.MaxUint8 {
|
||||
return EncodeUint8(uint8(i))
|
||||
} else if i <= math.MaxUint16 {
|
||||
return EncodeUint16(uint16(i))
|
||||
} else if i <= math.MaxUint32 {
|
||||
return EncodeUint32(uint32(i))
|
||||
} else {
|
||||
return EncodeUint64(uint64(i))
|
||||
}
|
||||
return LeEncodeUint(i)
|
||||
}
|
||||
|
||||
func EncodeInt8(i int8) []byte {
|
||||
return []byte{byte(i)}
|
||||
return LeEncodeInt8(i)
|
||||
}
|
||||
|
||||
func EncodeUint8(i uint8) []byte {
|
||||
return []byte{byte(i)}
|
||||
return LeEncodeUint8(i)
|
||||
}
|
||||
|
||||
func EncodeInt16(i int16) []byte {
|
||||
bytes := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(bytes, uint16(i))
|
||||
return bytes
|
||||
return LeEncodeInt16(i)
|
||||
}
|
||||
|
||||
func EncodeUint16(i uint16) []byte {
|
||||
bytes := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(bytes, i)
|
||||
return bytes
|
||||
return LeEncodeUint16(i)
|
||||
}
|
||||
|
||||
func EncodeInt32(i int32) []byte {
|
||||
bytes := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(bytes, uint32(i))
|
||||
return bytes
|
||||
return LeEncodeInt32(i)
|
||||
}
|
||||
|
||||
func EncodeUint32(i uint32) []byte {
|
||||
bytes := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(bytes, i)
|
||||
return bytes
|
||||
return LeEncodeUint32(i)
|
||||
}
|
||||
|
||||
func EncodeInt64(i int64) []byte {
|
||||
bytes := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(bytes, uint64(i))
|
||||
return bytes
|
||||
return LeEncodeInt64(i)
|
||||
}
|
||||
|
||||
func EncodeUint64(i uint64) []byte {
|
||||
bytes := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(bytes, i)
|
||||
return bytes
|
||||
return LeEncodeUint64(i)
|
||||
}
|
||||
|
||||
func EncodeFloat32(f float32) []byte {
|
||||
bits := math.Float32bits(f)
|
||||
bytes := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(bytes, bits)
|
||||
return bytes
|
||||
return LeEncodeFloat32(f)
|
||||
}
|
||||
|
||||
func EncodeFloat64(f float64) []byte {
|
||||
bits := math.Float64bits(f)
|
||||
bytes := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(bytes, bits)
|
||||
return bytes
|
||||
return LeEncodeFloat64(f)
|
||||
}
|
||||
|
||||
// 当b位数不够时,进行高位补0
|
||||
func fillUpSize(b []byte, l int) []byte {
|
||||
if len(b) >= l {
|
||||
return b
|
||||
}
|
||||
c := make([]byte, 0)
|
||||
c = append(c, b...)
|
||||
for i := 0; i < l-len(b); i++ {
|
||||
c = append(c, 0x00)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// 将二进制解析为int类型,根据[]byte的长度进行自动转换.
|
||||
// 注意内部使用的是uint*,使用int会造成位丢失。
|
||||
func DecodeToInt(b []byte) int {
|
||||
if len(b) < 2 {
|
||||
return int(DecodeToUint8(b))
|
||||
} else if len(b) < 3 {
|
||||
return int(DecodeToUint16(b))
|
||||
} else if len(b) < 5 {
|
||||
return int(DecodeToUint32(b))
|
||||
} else {
|
||||
return int(DecodeToUint64(b))
|
||||
}
|
||||
return LeDecodeToInt(b)
|
||||
}
|
||||
|
||||
// 将二进制解析为uint类型,根据[]byte的长度进行自动转换
|
||||
func DecodeToUint(b []byte) uint {
|
||||
if len(b) < 2 {
|
||||
return uint(DecodeToUint8(b))
|
||||
} else if len(b) < 3 {
|
||||
return uint(DecodeToUint16(b))
|
||||
} else if len(b) < 5 {
|
||||
return uint(DecodeToUint32(b))
|
||||
} else {
|
||||
return uint(DecodeToUint64(b))
|
||||
}
|
||||
return LeDecodeToUint(b)
|
||||
}
|
||||
|
||||
// 将二进制解析为bool类型,识别标准是判断二进制中数值是否都为0,或者为空
|
||||
func DecodeToBool(b []byte) bool {
|
||||
if len(b) == 0 {
|
||||
return false
|
||||
}
|
||||
if bytes.Compare(b, make([]byte, len(b))) == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return LeDecodeToBool(b)
|
||||
}
|
||||
|
||||
func DecodeToInt8(b []byte) int8 {
|
||||
return int8(b[0])
|
||||
return LeDecodeToInt8(b)
|
||||
}
|
||||
|
||||
func DecodeToUint8(b []byte) uint8 {
|
||||
return uint8(b[0])
|
||||
return LeDecodeToUint8(b)
|
||||
}
|
||||
|
||||
func DecodeToInt16(b []byte) int16 {
|
||||
return int16(binary.LittleEndian.Uint16(fillUpSize(b, 2)))
|
||||
return LeDecodeToInt16(b)
|
||||
}
|
||||
|
||||
func DecodeToUint16(b []byte) uint16 {
|
||||
return binary.LittleEndian.Uint16(fillUpSize(b, 2))
|
||||
return LeDecodeToUint16(b)
|
||||
}
|
||||
|
||||
func DecodeToInt32(b []byte) int32 {
|
||||
return int32(binary.LittleEndian.Uint32(fillUpSize(b, 4)))
|
||||
return LeDecodeToInt32(b)
|
||||
}
|
||||
|
||||
func DecodeToUint32(b []byte) uint32 {
|
||||
return binary.LittleEndian.Uint32(fillUpSize(b, 4))
|
||||
return LeDecodeToUint32(b)
|
||||
}
|
||||
|
||||
func DecodeToInt64(b []byte) int64 {
|
||||
return int64(binary.LittleEndian.Uint64(fillUpSize(b, 8)))
|
||||
return LeDecodeToInt64(b)
|
||||
}
|
||||
|
||||
func DecodeToUint64(b []byte) uint64 {
|
||||
return binary.LittleEndian.Uint64(fillUpSize(b, 8))
|
||||
return LeDecodeToUint64(b)
|
||||
}
|
||||
|
||||
func DecodeToFloat32(b []byte) float32 {
|
||||
return math.Float32frombits(binary.LittleEndian.Uint32(fillUpSize(b, 4)))
|
||||
return LeDecodeToFloat32(b)
|
||||
}
|
||||
|
||||
func DecodeToFloat64(b []byte) float64 {
|
||||
return math.Float64frombits(binary.LittleEndian.Uint64(fillUpSize(b, 8)))
|
||||
}
|
||||
|
||||
// 默认编码
|
||||
func EncodeBits(bits []Bit, i int, l int) []Bit {
|
||||
return EncodeBitsWithUint(bits, uint(i), l)
|
||||
}
|
||||
|
||||
// 将ui按位合并到bits数组中,并占length长度位(注意:uis数组中存放的是二进制的0|1数字)
|
||||
func EncodeBitsWithUint(bits []Bit, ui uint, l int) []Bit {
|
||||
a := make([]Bit, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
a[i] = Bit(ui & 1)
|
||||
ui >>= 1
|
||||
}
|
||||
if bits != nil {
|
||||
return append(bits, a...)
|
||||
} else {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
// 将bits转换为[]byte,从左至右进行编码,不足1 byte按0往末尾补充
|
||||
func EncodeBitsToBytes(bits []Bit) []byte {
|
||||
if len(bits)%8 != 0 {
|
||||
for i := 0; i < len(bits)%8; i++ {
|
||||
bits = append(bits, 0)
|
||||
}
|
||||
}
|
||||
b := make([]byte, 0)
|
||||
for i := 0; i < len(bits); i += 8 {
|
||||
b = append(b, byte(DecodeBitsToUint(bits[i:i+8])))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// 解析为int
|
||||
func DecodeBits(bits []Bit) int {
|
||||
v := int(0)
|
||||
for _, i := range bits {
|
||||
v = v<<1 | int(i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// 解析为uint
|
||||
func DecodeBitsToUint(bits []Bit) uint {
|
||||
v := uint(0)
|
||||
for _, i := range bits {
|
||||
v = v<<1 | uint(i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// 解析[]byte为字位数组[]uint8
|
||||
func DecodeBytesToBits(bs []byte) []Bit {
|
||||
bits := make([]Bit, 0)
|
||||
for _, b := range bs {
|
||||
bits = EncodeBitsWithUint(bits, uint(b), 8)
|
||||
}
|
||||
return bits
|
||||
return LeDecodeToFloat64(b)
|
||||
}
|
||||
|
||||
278
g/encoding/gbinary/gbinary_be.go
Normal file
278
g/encoding/gbinary/gbinary_be.go
Normal file
@ -0,0 +1,278 @@
|
||||
// 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 gbinary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// 针对基本类型进行二进制打包,支持的基本数据类型包括:
|
||||
// int/8/16/32/64、uint/8/16/32/64、float32/64、bool、string、[]byte。
|
||||
// 其他未知类型使用 fmt.Sprintf("%v", value) 转换为字符串之后处理。
|
||||
func BeEncode(values ...interface{}) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
for i := 0; i < len(values); i++ {
|
||||
if values[i] == nil {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
switch value := values[i].(type) {
|
||||
case int:
|
||||
buf.Write(BeEncodeInt(value))
|
||||
case int8:
|
||||
buf.Write(BeEncodeInt8(value))
|
||||
case int16:
|
||||
buf.Write(BeEncodeInt16(value))
|
||||
case int32:
|
||||
buf.Write(BeEncodeInt32(value))
|
||||
case int64:
|
||||
buf.Write(BeEncodeInt64(value))
|
||||
case uint:
|
||||
buf.Write(BeEncodeUint(value))
|
||||
case uint8:
|
||||
buf.Write(BeEncodeUint8(value))
|
||||
case uint16:
|
||||
buf.Write(BeEncodeUint16(value))
|
||||
case uint32:
|
||||
buf.Write(BeEncodeUint32(value))
|
||||
case uint64:
|
||||
buf.Write(BeEncodeUint64(value))
|
||||
case bool:
|
||||
buf.Write(BeEncodeBool(value))
|
||||
case string:
|
||||
buf.Write(BeEncodeString(value))
|
||||
case []byte:
|
||||
buf.Write(value)
|
||||
case float32:
|
||||
buf.Write(BeEncodeFloat32(value))
|
||||
case float64:
|
||||
buf.Write(BeEncodeFloat64(value))
|
||||
default:
|
||||
if err := binary.Write(buf, binary.BigEndian, value); err != nil {
|
||||
buf.Write(BeEncodeString(fmt.Sprintf("%v", value)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// 将变量转换为二进制[]byte,并指定固定的[]byte长度返回,长度单位为字节(byte);
|
||||
// 如果转换的二进制长度超过指定长度,那么进行截断处理
|
||||
func BeEncodeByLength(length int, values ...interface{}) []byte {
|
||||
b := BeEncode(values...)
|
||||
if len(b) < length {
|
||||
b = append(b, make([]byte, length-len(b))...)
|
||||
} else if len(b) > length {
|
||||
b = b[0:length]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// 整形二进制解包,注意第二个及其后参数为字长确定的整形变量的指针地址,以便确定解析的[]byte长度,
|
||||
// 例如:int8/16/32/64、uint8/16/32/64、float32/64等等
|
||||
func BeDecode(b []byte, values ...interface{}) error {
|
||||
buf := bytes.NewBuffer(b)
|
||||
for i := 0; i < len(values); i++ {
|
||||
err := binary.Read(buf, binary.BigEndian, values[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func BeEncodeString(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
|
||||
func BeDecodeToString(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func BeEncodeBool(b bool) []byte {
|
||||
if b == true {
|
||||
return []byte{1}
|
||||
} else {
|
||||
return []byte{0}
|
||||
}
|
||||
}
|
||||
|
||||
// 自动识别int类型长度,转换为[]byte
|
||||
func BeEncodeInt(i int) []byte {
|
||||
if i <= math.MaxInt8 {
|
||||
return BeEncodeInt8(int8(i))
|
||||
} else if i <= math.MaxInt16 {
|
||||
return BeEncodeInt16(int16(i))
|
||||
} else if i <= math.MaxInt32 {
|
||||
return BeEncodeInt32(int32(i))
|
||||
} else {
|
||||
return BeEncodeInt64(int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
// 自动识别uint类型长度,转换为[]byte
|
||||
func BeEncodeUint(i uint) []byte {
|
||||
if i <= math.MaxUint8 {
|
||||
return BeEncodeUint8(uint8(i))
|
||||
} else if i <= math.MaxUint16 {
|
||||
return BeEncodeUint16(uint16(i))
|
||||
} else if i <= math.MaxUint32 {
|
||||
return BeEncodeUint32(uint32(i))
|
||||
} else {
|
||||
return BeEncodeUint64(uint64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func BeEncodeInt8(i int8) []byte {
|
||||
return []byte{byte(i)}
|
||||
}
|
||||
|
||||
func BeEncodeUint8(i uint8) []byte {
|
||||
return []byte{byte(i)}
|
||||
}
|
||||
|
||||
func BeEncodeInt16(i int16) []byte {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, uint16(i))
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeUint16(i uint16) []byte {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeInt32(i int32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, uint32(i))
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeUint32(i uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeInt64(i int64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, uint64(i))
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeUint64(i uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeFloat32(f float32) []byte {
|
||||
bits := math.Float32bits(f)
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, bits)
|
||||
return b
|
||||
}
|
||||
|
||||
func BeEncodeFloat64(f float64) []byte {
|
||||
bits := math.Float64bits(f)
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, bits)
|
||||
return b
|
||||
}
|
||||
|
||||
// 将二进制解析为int类型,根据[]byte的长度进行自动转换.
|
||||
// 注意内部使用的是uint*,使用int会造成位丢失。
|
||||
func BeDecodeToInt(b []byte) int {
|
||||
if len(b) < 2 {
|
||||
return int(BeDecodeToUint8(b))
|
||||
} else if len(b) < 3 {
|
||||
return int(BeDecodeToUint16(b))
|
||||
} else if len(b) < 5 {
|
||||
return int(BeDecodeToUint32(b))
|
||||
} else {
|
||||
return int(BeDecodeToUint64(b))
|
||||
}
|
||||
}
|
||||
|
||||
// 将二进制解析为uint类型,根据[]byte的长度进行自动转换
|
||||
func BeDecodeToUint(b []byte) uint {
|
||||
if len(b) < 2 {
|
||||
return uint(BeDecodeToUint8(b))
|
||||
} else if len(b) < 3 {
|
||||
return uint(BeDecodeToUint16(b))
|
||||
} else if len(b) < 5 {
|
||||
return uint(BeDecodeToUint32(b))
|
||||
} else {
|
||||
return uint(BeDecodeToUint64(b))
|
||||
}
|
||||
}
|
||||
|
||||
// 将二进制解析为bool类型,识别标准是判断二进制中数值是否都为0,或者为空。
|
||||
func BeDecodeToBool(b []byte) bool {
|
||||
if len(b) == 0 {
|
||||
return false
|
||||
}
|
||||
if bytes.Compare(b, make([]byte, len(b))) == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func BeDecodeToInt8(b []byte) int8 {
|
||||
return int8(b[0])
|
||||
}
|
||||
|
||||
func BeDecodeToUint8(b []byte) uint8 {
|
||||
return uint8(b[0])
|
||||
}
|
||||
|
||||
func BeDecodeToInt16(b []byte) int16 {
|
||||
return int16(binary.BigEndian.Uint16(BeFillUpSize(b, 2)))
|
||||
}
|
||||
|
||||
func BeDecodeToUint16(b []byte) uint16 {
|
||||
return binary.BigEndian.Uint16(BeFillUpSize(b, 2))
|
||||
}
|
||||
|
||||
func BeDecodeToInt32(b []byte) int32 {
|
||||
return int32(binary.BigEndian.Uint32(BeFillUpSize(b, 4)))
|
||||
}
|
||||
|
||||
func BeDecodeToUint32(b []byte) uint32 {
|
||||
return binary.BigEndian.Uint32(BeFillUpSize(b, 4))
|
||||
}
|
||||
|
||||
func BeDecodeToInt64(b []byte) int64 {
|
||||
return int64(binary.BigEndian.Uint64(BeFillUpSize(b, 8)))
|
||||
}
|
||||
|
||||
func BeDecodeToUint64(b []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(BeFillUpSize(b, 8))
|
||||
}
|
||||
|
||||
func BeDecodeToFloat32(b []byte) float32 {
|
||||
return math.Float32frombits(binary.BigEndian.Uint32(BeFillUpSize(b, 4)))
|
||||
}
|
||||
|
||||
func BeDecodeToFloat64(b []byte) float64 {
|
||||
return math.Float64frombits(binary.BigEndian.Uint64(BeFillUpSize(b, 8)))
|
||||
}
|
||||
|
||||
// 当b位数不够时,进行低位补0。
|
||||
// 注意这里为了不影响原有输入参数,是采用的值复制设计。
|
||||
func BeFillUpSize(b []byte, l int) []byte {
|
||||
if len(b) >= l {
|
||||
return b[:l]
|
||||
}
|
||||
c := make([]byte, l)
|
||||
copy(c[l-len(b):], b)
|
||||
return c
|
||||
}
|
||||
72
g/encoding/gbinary/gbinary_bits.go
Normal file
72
g/encoding/gbinary/gbinary_bits.go
Normal file
@ -0,0 +1,72 @@
|
||||
// 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 gbinary
|
||||
|
||||
// 实验特性
|
||||
|
||||
// 二进制位(0|1)
|
||||
type Bit int8
|
||||
|
||||
// 默认编码
|
||||
func EncodeBits(bits []Bit, i int, l int) []Bit {
|
||||
return EncodeBitsWithUint(bits, uint(i), l)
|
||||
}
|
||||
|
||||
// 将ui按位合并到bits数组中,并占length长度位(注意:uis数组中存放的是二进制的0|1数字)
|
||||
func EncodeBitsWithUint(bits []Bit, ui uint, l int) []Bit {
|
||||
a := make([]Bit, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
a[i] = Bit(ui & 1)
|
||||
ui >>= 1
|
||||
}
|
||||
if bits != nil {
|
||||
return append(bits, a...)
|
||||
} else {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
// 将bits转换为[]byte,从左至右进行编码,不足1 byte按0往末尾补充
|
||||
func EncodeBitsToBytes(bits []Bit) []byte {
|
||||
if len(bits)%8 != 0 {
|
||||
for i := 0; i < len(bits)%8; i++ {
|
||||
bits = append(bits, 0)
|
||||
}
|
||||
}
|
||||
b := make([]byte, 0)
|
||||
for i := 0; i < len(bits); i += 8 {
|
||||
b = append(b, byte(DecodeBitsToUint(bits[i:i+8])))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// 解析为int
|
||||
func DecodeBits(bits []Bit) int {
|
||||
v := int(0)
|
||||
for _, i := range bits {
|
||||
v = v<<1 | int(i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// 解析为uint
|
||||
func DecodeBitsToUint(bits []Bit) uint {
|
||||
v := uint(0)
|
||||
for _, i := range bits {
|
||||
v = v<<1 | uint(i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// 解析[]byte为字位数组[]uint8
|
||||
func DecodeBytesToBits(bs []byte) []Bit {
|
||||
bits := make([]Bit, 0)
|
||||
for _, b := range bs {
|
||||
bits = EncodeBitsWithUint(bits, uint(b), 8)
|
||||
}
|
||||
return bits
|
||||
}
|
||||
7
g/encoding/gbinary/gbinary_func.go
Normal file
7
g/encoding/gbinary/gbinary_func.go
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2019 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 gbinary
|
||||
278
g/encoding/gbinary/gbinary_le.go
Normal file
278
g/encoding/gbinary/gbinary_le.go
Normal file
@ -0,0 +1,278 @@
|
||||
// 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 gbinary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// 针对基本类型进行二进制打包,支持的基本数据类型包括:
|
||||
// int/8/16/32/64、uint/8/16/32/64、float32/64、bool、string、[]byte。
|
||||
// 其他未知类型使用 fmt.Sprintf("%v", value) 转换为字符串之后处理。
|
||||
func LeEncode(values ...interface{}) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
for i := 0; i < len(values); i++ {
|
||||
if values[i] == nil {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
switch value := values[i].(type) {
|
||||
case int:
|
||||
buf.Write(LeEncodeInt(value))
|
||||
case int8:
|
||||
buf.Write(LeEncodeInt8(value))
|
||||
case int16:
|
||||
buf.Write(LeEncodeInt16(value))
|
||||
case int32:
|
||||
buf.Write(LeEncodeInt32(value))
|
||||
case int64:
|
||||
buf.Write(LeEncodeInt64(value))
|
||||
case uint:
|
||||
buf.Write(LeEncodeUint(value))
|
||||
case uint8:
|
||||
buf.Write(LeEncodeUint8(value))
|
||||
case uint16:
|
||||
buf.Write(LeEncodeUint16(value))
|
||||
case uint32:
|
||||
buf.Write(LeEncodeUint32(value))
|
||||
case uint64:
|
||||
buf.Write(LeEncodeUint64(value))
|
||||
case bool:
|
||||
buf.Write(LeEncodeBool(value))
|
||||
case string:
|
||||
buf.Write(LeEncodeString(value))
|
||||
case []byte:
|
||||
buf.Write(value)
|
||||
case float32:
|
||||
buf.Write(LeEncodeFloat32(value))
|
||||
case float64:
|
||||
buf.Write(LeEncodeFloat64(value))
|
||||
default:
|
||||
if err := binary.Write(buf, binary.LittleEndian, value); err != nil {
|
||||
buf.Write(LeEncodeString(fmt.Sprintf("%v", value)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// 将变量转换为二进制[]byte,并指定固定的[]byte长度返回,长度单位为字节(byte);
|
||||
// 如果转换的二进制长度超过指定长度,那么进行截断处理
|
||||
func LeEncodeByLength(length int, values ...interface{}) []byte {
|
||||
b := LeEncode(values...)
|
||||
if len(b) < length {
|
||||
b = append(b, make([]byte, length-len(b))...)
|
||||
} else if len(b) > length {
|
||||
b = b[0:length]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// 整形二进制解包,注意第二个及其后参数为字长确定的整形变量的指针地址,以便确定解析的[]byte长度,
|
||||
// 例如:int8/16/32/64、uint8/16/32/64、float32/64等等
|
||||
func LeDecode(b []byte, values ...interface{}) error {
|
||||
buf := bytes.NewBuffer(b)
|
||||
for i := 0; i < len(values); i++ {
|
||||
err := binary.Read(buf, binary.LittleEndian, values[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LeEncodeString(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
|
||||
func LeDecodeToString(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func LeEncodeBool(b bool) []byte {
|
||||
if b == true {
|
||||
return []byte{1}
|
||||
} else {
|
||||
return []byte{0}
|
||||
}
|
||||
}
|
||||
|
||||
// 自动识别int类型长度,转换为[]byte
|
||||
func LeEncodeInt(i int) []byte {
|
||||
if i <= math.MaxInt8 {
|
||||
return EncodeInt8(int8(i))
|
||||
} else if i <= math.MaxInt16 {
|
||||
return EncodeInt16(int16(i))
|
||||
} else if i <= math.MaxInt32 {
|
||||
return EncodeInt32(int32(i))
|
||||
} else {
|
||||
return EncodeInt64(int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
// 自动识别uint类型长度,转换为[]byte
|
||||
func LeEncodeUint(i uint) []byte {
|
||||
if i <= math.MaxUint8 {
|
||||
return EncodeUint8(uint8(i))
|
||||
} else if i <= math.MaxUint16 {
|
||||
return EncodeUint16(uint16(i))
|
||||
} else if i <= math.MaxUint32 {
|
||||
return EncodeUint32(uint32(i))
|
||||
} else {
|
||||
return EncodeUint64(uint64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func LeEncodeInt8(i int8) []byte {
|
||||
return []byte{byte(i)}
|
||||
}
|
||||
|
||||
func LeEncodeUint8(i uint8) []byte {
|
||||
return []byte{byte(i)}
|
||||
}
|
||||
|
||||
func LeEncodeInt16(i int16) []byte {
|
||||
b := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(b, uint16(i))
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeUint16(i uint16) []byte {
|
||||
b := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeInt32(i int32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, uint32(i))
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeUint32(i uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeInt64(i int64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, uint64(i))
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeUint64(i uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeFloat32(f float32) []byte {
|
||||
bits := math.Float32bits(f)
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, bits)
|
||||
return b
|
||||
}
|
||||
|
||||
func LeEncodeFloat64(f float64) []byte {
|
||||
bits := math.Float64bits(f)
|
||||
b := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, bits)
|
||||
return b
|
||||
}
|
||||
|
||||
// 将二进制解析为int类型,根据[]byte的长度进行自动转换.
|
||||
// 注意内部使用的是uint*,使用int会造成位丢失。
|
||||
func LeDecodeToInt(b []byte) int {
|
||||
if len(b) < 2 {
|
||||
return int(LeDecodeToUint8(b))
|
||||
} else if len(b) < 3 {
|
||||
return int(LeDecodeToUint16(b))
|
||||
} else if len(b) < 5 {
|
||||
return int(LeDecodeToUint32(b))
|
||||
} else {
|
||||
return int(LeDecodeToUint64(b))
|
||||
}
|
||||
}
|
||||
|
||||
// 将二进制解析为uint类型,根据[]byte的长度进行自动转换
|
||||
func LeDecodeToUint(b []byte) uint {
|
||||
if len(b) < 2 {
|
||||
return uint(LeDecodeToUint8(b))
|
||||
} else if len(b) < 3 {
|
||||
return uint(LeDecodeToUint16(b))
|
||||
} else if len(b) < 5 {
|
||||
return uint(LeDecodeToUint32(b))
|
||||
} else {
|
||||
return uint(LeDecodeToUint64(b))
|
||||
}
|
||||
}
|
||||
|
||||
// 将二进制解析为bool类型,识别标准是判断二进制中数值是否都为0,或者为空。
|
||||
func LeDecodeToBool(b []byte) bool {
|
||||
if len(b) == 0 {
|
||||
return false
|
||||
}
|
||||
if bytes.Compare(b, make([]byte, len(b))) == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func LeDecodeToInt8(b []byte) int8 {
|
||||
return int8(b[0])
|
||||
}
|
||||
|
||||
func LeDecodeToUint8(b []byte) uint8 {
|
||||
return uint8(b[0])
|
||||
}
|
||||
|
||||
func LeDecodeToInt16(b []byte) int16 {
|
||||
return int16(binary.LittleEndian.Uint16(LeFillUpSize(b, 2)))
|
||||
}
|
||||
|
||||
func LeDecodeToUint16(b []byte) uint16 {
|
||||
return binary.LittleEndian.Uint16(LeFillUpSize(b, 2))
|
||||
}
|
||||
|
||||
func LeDecodeToInt32(b []byte) int32 {
|
||||
return int32(binary.LittleEndian.Uint32(LeFillUpSize(b, 4)))
|
||||
}
|
||||
|
||||
func LeDecodeToUint32(b []byte) uint32 {
|
||||
return binary.LittleEndian.Uint32(LeFillUpSize(b, 4))
|
||||
}
|
||||
|
||||
func LeDecodeToInt64(b []byte) int64 {
|
||||
return int64(binary.LittleEndian.Uint64(LeFillUpSize(b, 8)))
|
||||
}
|
||||
|
||||
func LeDecodeToUint64(b []byte) uint64 {
|
||||
return binary.LittleEndian.Uint64(LeFillUpSize(b, 8))
|
||||
}
|
||||
|
||||
func LeDecodeToFloat32(b []byte) float32 {
|
||||
return math.Float32frombits(binary.LittleEndian.Uint32(LeFillUpSize(b, 4)))
|
||||
}
|
||||
|
||||
func LeDecodeToFloat64(b []byte) float64 {
|
||||
return math.Float64frombits(binary.LittleEndian.Uint64(LeFillUpSize(b, 8)))
|
||||
}
|
||||
|
||||
// 当b位数不够时,进行高位补0。
|
||||
// 注意这里为了不影响原有输入参数,是采用的值复制设计。
|
||||
func LeFillUpSize(b []byte, l int) []byte {
|
||||
if len(b) >= l {
|
||||
return b[:l]
|
||||
}
|
||||
c := make([]byte, l)
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
84
g/encoding/gbinary/gbinary_z_be_test.go
Normal file
84
g/encoding/gbinary/gbinary_z_be_test.go
Normal file
@ -0,0 +1,84 @@
|
||||
// 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 gbinary_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func Test_BeEncodeAndBeDecode(t *testing.T) {
|
||||
for k, v := range testData {
|
||||
ve := gbinary.BeEncode(v)
|
||||
ve1 := gbinary.BeEncodeByLength(len(ve), v)
|
||||
|
||||
//t.Logf("%s:%v, encoded:%v\n", k, v, ve)
|
||||
switch v.(type) {
|
||||
case int:
|
||||
gtest.Assert(gbinary.BeDecodeToInt(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToInt(ve1), v)
|
||||
case int8:
|
||||
gtest.Assert(gbinary.BeDecodeToInt8(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToInt8(ve1), v)
|
||||
case int16:
|
||||
gtest.Assert(gbinary.BeDecodeToInt16(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToInt16(ve1), v)
|
||||
case int32:
|
||||
gtest.Assert(gbinary.BeDecodeToInt32(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToInt32(ve1), v)
|
||||
case int64:
|
||||
gtest.Assert(gbinary.BeDecodeToInt64(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToInt64(ve1), v)
|
||||
case uint:
|
||||
gtest.Assert(gbinary.BeDecodeToUint(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToUint(ve1), v)
|
||||
case uint8:
|
||||
gtest.Assert(gbinary.BeDecodeToUint8(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToUint8(ve1), v)
|
||||
case uint16:
|
||||
gtest.Assert(gbinary.BeDecodeToUint16(ve1), v)
|
||||
gtest.Assert(gbinary.BeDecodeToUint16(ve), v)
|
||||
case uint32:
|
||||
gtest.Assert(gbinary.BeDecodeToUint32(ve1), v)
|
||||
gtest.Assert(gbinary.BeDecodeToUint32(ve), v)
|
||||
case uint64:
|
||||
gtest.Assert(gbinary.BeDecodeToUint64(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToUint64(ve1), v)
|
||||
case bool:
|
||||
gtest.Assert(gbinary.BeDecodeToBool(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToBool(ve1), v)
|
||||
case string:
|
||||
gtest.Assert(gbinary.BeDecodeToString(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToString(ve1), v)
|
||||
case float32:
|
||||
gtest.Assert(gbinary.BeDecodeToFloat32(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToFloat32(ve1), v)
|
||||
case float64:
|
||||
gtest.Assert(gbinary.BeDecodeToFloat64(ve), v)
|
||||
gtest.Assert(gbinary.BeDecodeToFloat64(ve1), v)
|
||||
default:
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
res := make([]byte, len(ve))
|
||||
err := gbinary.BeDecode(ve, res)
|
||||
if err != nil {
|
||||
t.Errorf("test data: %s, %v, error:%v", k, v, err)
|
||||
}
|
||||
gtest.Assert(res, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_BeEncodeStruct(t *testing.T) {
|
||||
user := User{"wenzi1", 999, "www.baidu.com"}
|
||||
ve := gbinary.BeEncode(user)
|
||||
s := gbinary.BeDecodeToString(ve)
|
||||
gtest.Assert(string(s), s)
|
||||
}
|
||||
84
g/encoding/gbinary/gbinary_z_le_test.go
Normal file
84
g/encoding/gbinary/gbinary_z_le_test.go
Normal file
@ -0,0 +1,84 @@
|
||||
// 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 gbinary_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func Test_LeEncodeAndLeDecode(t *testing.T) {
|
||||
for k, v := range testData {
|
||||
ve := gbinary.LeEncode(v)
|
||||
ve1 := gbinary.LeEncodeByLength(len(ve), v)
|
||||
|
||||
//t.Logf("%s:%v, encoded:%v\n", k, v, ve)
|
||||
switch v.(type) {
|
||||
case int:
|
||||
gtest.Assert(gbinary.LeDecodeToInt(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToInt(ve1), v)
|
||||
case int8:
|
||||
gtest.Assert(gbinary.LeDecodeToInt8(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToInt8(ve1), v)
|
||||
case int16:
|
||||
gtest.Assert(gbinary.LeDecodeToInt16(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToInt16(ve1), v)
|
||||
case int32:
|
||||
gtest.Assert(gbinary.LeDecodeToInt32(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToInt32(ve1), v)
|
||||
case int64:
|
||||
gtest.Assert(gbinary.LeDecodeToInt64(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToInt64(ve1), v)
|
||||
case uint:
|
||||
gtest.Assert(gbinary.LeDecodeToUint(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToUint(ve1), v)
|
||||
case uint8:
|
||||
gtest.Assert(gbinary.LeDecodeToUint8(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToUint8(ve1), v)
|
||||
case uint16:
|
||||
gtest.Assert(gbinary.LeDecodeToUint16(ve1), v)
|
||||
gtest.Assert(gbinary.LeDecodeToUint16(ve), v)
|
||||
case uint32:
|
||||
gtest.Assert(gbinary.LeDecodeToUint32(ve1), v)
|
||||
gtest.Assert(gbinary.LeDecodeToUint32(ve), v)
|
||||
case uint64:
|
||||
gtest.Assert(gbinary.LeDecodeToUint64(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToUint64(ve1), v)
|
||||
case bool:
|
||||
gtest.Assert(gbinary.LeDecodeToBool(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToBool(ve1), v)
|
||||
case string:
|
||||
gtest.Assert(gbinary.LeDecodeToString(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToString(ve1), v)
|
||||
case float32:
|
||||
gtest.Assert(gbinary.LeDecodeToFloat32(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToFloat32(ve1), v)
|
||||
case float64:
|
||||
gtest.Assert(gbinary.LeDecodeToFloat64(ve), v)
|
||||
gtest.Assert(gbinary.LeDecodeToFloat64(ve1), v)
|
||||
default:
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
res := make([]byte, len(ve))
|
||||
err := gbinary.LeDecode(ve, res)
|
||||
if err != nil {
|
||||
t.Errorf("test data: %s, %v, error:%v", k, v, err)
|
||||
}
|
||||
gtest.Assert(res, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_LeEncodeStruct(t *testing.T) {
|
||||
user := User{"wenzi1", 999, "www.baidu.com"}
|
||||
ve := gbinary.LeEncode(user)
|
||||
s := gbinary.LeDecodeToString(ve)
|
||||
gtest.Assert(string(s), s)
|
||||
}
|
||||
@ -7,12 +7,19 @@
|
||||
package gbinary_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Url string
|
||||
}
|
||||
|
||||
var testData = map[string]interface{}{
|
||||
//"nil": nil,
|
||||
"int": int(123),
|
||||
@ -39,7 +46,9 @@ var testData = map[string]interface{}{
|
||||
"float64": float64(123.456),
|
||||
}
|
||||
|
||||
func TestEncodeAndDecode(t *testing.T) {
|
||||
var testBitData = []int{0, 99, 122, 129, 222, 999, 22322}
|
||||
|
||||
func Test_EncodeAndDecode(t *testing.T) {
|
||||
for k, v := range testData {
|
||||
ve := gbinary.Encode(v)
|
||||
ve1 := gbinary.EncodeByLength(len(ve), v)
|
||||
@ -102,22 +111,14 @@ func TestEncodeAndDecode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Url string
|
||||
}
|
||||
|
||||
func TestEncodeStruct(t *testing.T) {
|
||||
func Test_EncodeStruct(t *testing.T) {
|
||||
user := User{"wenzi1", 999, "www.baidu.com"}
|
||||
ve := gbinary.Encode(user)
|
||||
s := gbinary.DecodeToString(ve)
|
||||
gtest.Assert(string(s), s)
|
||||
}
|
||||
|
||||
var testBitData = []int{0, 99, 122, 129, 222, 999, 22322}
|
||||
|
||||
func TestBits(t *testing.T) {
|
||||
func Test_Bits(t *testing.T) {
|
||||
for i := range testBitData {
|
||||
bits := make([]gbinary.Bit, 0)
|
||||
res := gbinary.EncodeBits(bits, testBitData[i], 64)
|
||||
@ -266,11 +266,32 @@ func (j *Json) GetToVar(pattern string, pointer interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetToStruct gets the value by specified <pattern>,
|
||||
// and converts it to specified object <objPointer>.
|
||||
// The <objPointer> should be the pointer to an object.
|
||||
func (j *Json) GetToStruct(pattern string, pointer interface{}) error {
|
||||
return gconv.Struct(j.Get(pattern), pointer)
|
||||
// GetStruct gets the value by specified <pattern>,
|
||||
// and converts it to specified object <pointer>.
|
||||
// The <pointer> should be the pointer to an object.
|
||||
func (j *Json) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Struct(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructDeep does GetStruct recursively.
|
||||
func (j *Json) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.StructDeep(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructs converts any slice to given struct slice.
|
||||
func (j *Json) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Structs(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructsDeep converts any slice to given struct slice recursively.
|
||||
func (j *Json) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.StructsDeep(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetToStruct is alias of GetStruct.
|
||||
// Deprecated.
|
||||
func (j *Json) GetToStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return j.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// ToMap converts current Json object to map[string]interface{}.
|
||||
@ -290,7 +311,7 @@ func (j *Json) ToArray() []interface{} {
|
||||
}
|
||||
|
||||
// ToStruct converts current Json object to specified object.
|
||||
// The <objPointer> should be a pointer type.
|
||||
// The <pointer> should be a pointer type.
|
||||
func (j *Json) ToStruct(pointer interface{}) error {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
|
||||
@ -145,11 +145,32 @@ func (p *Parser) GetToVar(pattern string, pointer interface{}) error {
|
||||
return p.json.GetToVar(pattern, pointer)
|
||||
}
|
||||
|
||||
// GetToStruct gets the value by specified <pattern>,
|
||||
// GetStruct gets the value by specified <pattern>,
|
||||
// and converts it to specified object <pointer>.
|
||||
// The <pointer> should be the pointer to a struct.
|
||||
func (p *Parser) GetToStruct(pattern string, pointer interface{}) error {
|
||||
return p.json.GetToStruct(pattern, pointer)
|
||||
// The <pointer> should be the pointer to an object.
|
||||
func (p *Parser) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructDeep does GetStruct recursively.
|
||||
func (p *Parser) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStructDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructs converts any slice to given struct slice.
|
||||
func (p *Parser) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStructs(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructsDeep converts any slice to given struct slice recursively.
|
||||
func (p *Parser) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStructsDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetToStruct is alias of GetStruct.
|
||||
// Deprecated.
|
||||
func (p *Parser) GetToStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// Set sets value with specified <pattern>.
|
||||
|
||||
@ -87,75 +87,34 @@ func Database(name ...string) gdb.DB {
|
||||
glog.Error(`database init failed: "database" node not found, is config file or configuration missing?`)
|
||||
return nil
|
||||
}
|
||||
for group, v := range m {
|
||||
// Parse <m> as map-slice.
|
||||
for group, groupConfig := range m {
|
||||
cg := gdb.ConfigGroup{}
|
||||
if list, ok := v.([]interface{}); ok {
|
||||
for _, nodeValue := range list {
|
||||
node := gdb.ConfigNode{}
|
||||
nodeMap := nodeValue.(map[string]interface{})
|
||||
if value, ok := nodeMap["host"]; ok {
|
||||
node.Host = gconv.String(value)
|
||||
switch value := groupConfig.(type) {
|
||||
case []interface{}:
|
||||
for _, v := range value {
|
||||
if node := parseDBConfigNode(v); node != nil {
|
||||
cg = append(cg, *node)
|
||||
}
|
||||
if value, ok := nodeMap["port"]; ok {
|
||||
node.Port = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["user"]; ok {
|
||||
node.User = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["pass"]; ok {
|
||||
node.Pass = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["name"]; ok {
|
||||
node.Name = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["type"]; ok {
|
||||
node.Type = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["role"]; ok {
|
||||
node.Role = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["charset"]; ok {
|
||||
node.Charset = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["priority"]; ok {
|
||||
node.Priority = gconv.Int(value)
|
||||
}
|
||||
// Deprecated
|
||||
if value, ok := nodeMap["linkinfo"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
// Deprecated
|
||||
if value, ok := nodeMap["link-info"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["linkInfo"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
// Deprecated
|
||||
if value, ok := nodeMap["max-idle"]; ok {
|
||||
node.MaxIdleConnCount = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["maxIdle"]; ok {
|
||||
node.MaxIdleConnCount = gconv.Int(value)
|
||||
}
|
||||
// Deprecated
|
||||
if value, ok := nodeMap["max-open"]; ok {
|
||||
node.MaxOpenConnCount = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["maxOpen"]; ok {
|
||||
node.MaxOpenConnCount = gconv.Int(value)
|
||||
}
|
||||
// Deprecated
|
||||
if value, ok := nodeMap["max-lifetime"]; ok {
|
||||
node.MaxConnLifetime = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["maxLifetime"]; ok {
|
||||
node.MaxConnLifetime = gconv.Int(value)
|
||||
}
|
||||
cg = append(cg, node)
|
||||
}
|
||||
case map[string]interface{}:
|
||||
if node := parseDBConfigNode(value); node != nil {
|
||||
cg = append(cg, *node)
|
||||
}
|
||||
}
|
||||
gdb.AddConfigGroup(group, cg)
|
||||
if len(cg) > 0 {
|
||||
gdb.AddConfigGroup(group, cg)
|
||||
}
|
||||
}
|
||||
// Parse <m> as a single node configuration.
|
||||
if node := parseDBConfigNode(m); node != nil {
|
||||
cg := gdb.ConfigGroup{}
|
||||
if node.LinkInfo != "" || node.Host != "" {
|
||||
cg = append(cg, *node)
|
||||
}
|
||||
if len(cg) > 0 {
|
||||
gdb.AddConfigGroup(group, cg)
|
||||
}
|
||||
}
|
||||
addConfigMonitor(key, config)
|
||||
}
|
||||
@ -172,6 +131,81 @@ func Database(name ...string) gdb.DB {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析数据库配置节点项
|
||||
func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
|
||||
nodeMap, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
node := &gdb.ConfigNode{}
|
||||
if value, ok := nodeMap["host"]; ok {
|
||||
node.Host = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["port"]; ok {
|
||||
node.Port = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["user"]; ok {
|
||||
node.User = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["pass"]; ok {
|
||||
node.Pass = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["name"]; ok {
|
||||
node.Name = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["type"]; ok {
|
||||
node.Type = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["role"]; ok {
|
||||
node.Role = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["charset"]; ok {
|
||||
node.Charset = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["priority"]; ok {
|
||||
node.Priority = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["linkinfo"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["link-info"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["linkInfo"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["link"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
}
|
||||
if value, ok := nodeMap["max-idle"]; ok {
|
||||
node.MaxIdleConnCount = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["maxIdle"]; ok {
|
||||
node.MaxIdleConnCount = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["max-open"]; ok {
|
||||
node.MaxOpenConnCount = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["maxOpen"]; ok {
|
||||
node.MaxOpenConnCount = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["max-lifetime"]; ok {
|
||||
node.MaxConnLifetime = gconv.Int(value)
|
||||
}
|
||||
if value, ok := nodeMap["maxLifetime"]; ok {
|
||||
node.MaxConnLifetime = gconv.Int(value)
|
||||
}
|
||||
// Parse link syntax.
|
||||
if node.LinkInfo != "" && node.Type == "" {
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.LinkInfo)
|
||||
if len(match) == 3 {
|
||||
node.Type = match[1]
|
||||
node.LinkInfo = match[2]
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// Redis操作对象,使用了连接池
|
||||
func Redis(name ...string) *gredis.Redis {
|
||||
config := Config()
|
||||
|
||||
@ -8,5 +8,5 @@
|
||||
package ghttp
|
||||
|
||||
var (
|
||||
paramTagPriority = []string{"param", "params"}
|
||||
paramTagPriority = []string{"param", "params", "p"}
|
||||
)
|
||||
|
||||
@ -154,5 +154,5 @@ func (r *Request) GetPostToStruct(pointer interface{}, mapping ...map[string]str
|
||||
for k, v := range r.GetPostMap() {
|
||||
params[k] = v
|
||||
}
|
||||
return gconv.Struct(params, pointer, tagMap)
|
||||
return gconv.StructDeep(params, pointer, tagMap)
|
||||
}
|
||||
|
||||
@ -489,14 +489,41 @@ func (c *Config) GetGTime(pattern string, format ...string) *gtime.Time {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) GetToStruct(pattern string, pointer interface{}, def ...interface{}) error {
|
||||
func (c *Config) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetToStruct(pattern, pointer)
|
||||
return j.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
// Deprecated. See Clear.
|
||||
func (c *Config) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetStructDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
func (c *Config) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetStructs(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
func (c *Config) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetStructsDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (c *Config) GetToStruct(pattern string, pointer interface{}) error {
|
||||
return c.GetStruct(pattern, pointer)
|
||||
}
|
||||
|
||||
// Reload is alias of Clear.
|
||||
// Deprecated.
|
||||
func (c *Config) Reload() {
|
||||
c.jsons.Clear()
|
||||
}
|
||||
|
||||
@ -11,11 +11,8 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
@ -24,6 +21,11 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -142,29 +144,109 @@ func Rename(src string, dst string) error {
|
||||
return Move(src, dst)
|
||||
}
|
||||
|
||||
// Copy file from <src> to <dst>.
|
||||
// Copy file/directory from <src> to <dst>.
|
||||
//
|
||||
// @TODO directory copy support.
|
||||
// If <src> is file, it calls CopyFile to implements copy feature,
|
||||
// or else it calls CopyDir.
|
||||
func Copy(src string, dst string) error {
|
||||
srcFile, err := Open(src)
|
||||
if IsFile(src) {
|
||||
return CopyFile(src, dst)
|
||||
}
|
||||
return CopyDir(src, dst)
|
||||
}
|
||||
|
||||
// CopyFile copies the contents of the file named src to the file named
|
||||
// by dst. The file will be created if it does not already exist. If the
|
||||
// destination file exists, all it's contents will be replaced by the contents
|
||||
// of the source file. The file mode will be copied from the source and
|
||||
// the copied data is synced/flushed to stable storage.
|
||||
// Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
|
||||
func CopyFile(src, dst string) (err error) {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if e := in.Close(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if e := out.Close(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = out.Sync()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = os.Chmod(dst, si.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
|
||||
// Source directory must exist, destination directory must *not* exist.
|
||||
// Symlinks are ignored and skipped.
|
||||
func CopyDir(src string, dst string) (err error) {
|
||||
src = filepath.Clean(src)
|
||||
dst = filepath.Clean(dst)
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
dstFile, err := Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
if !si.IsDir() {
|
||||
return fmt.Errorf("source is not a directory")
|
||||
}
|
||||
defer dstFile.Close()
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
_, err = os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
err = dstFile.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
return fmt.Errorf("destination already exists")
|
||||
}
|
||||
return nil
|
||||
err = os.MkdirAll(dst, si.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
entries, err := ioutil.ReadDir(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
if entry.IsDir() {
|
||||
err = CopyDir(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Skip symlinks.
|
||||
if entry.Mode()&os.ModeSymlink != 0 {
|
||||
continue
|
||||
}
|
||||
err = CopyFile(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DirNames returns sub-file names of given directory <path>.
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package gfile_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func TestIsDir(t *testing.T) {
|
||||
@ -677,3 +678,71 @@ func TestMainPkgPath(t *testing.T) {
|
||||
gtest.Assert(reads, "")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCopyFile(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var (
|
||||
paths string = "/testfile_copyfile1.txt"
|
||||
topath string = "/testfile_copyfile2.txt"
|
||||
)
|
||||
|
||||
createTestFile(paths, "")
|
||||
defer delTestFiles(paths)
|
||||
|
||||
gtest.Assert(gfile.CopyFile(testpath()+paths, testpath()+topath), nil)
|
||||
defer delTestFiles(topath)
|
||||
|
||||
gtest.Assert(gfile.IsFile(testpath()+topath), true)
|
||||
gtest.AssertNE(gfile.CopyFile("", ""), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCopyDir(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var (
|
||||
dirpath1 string = "/testcopydir1"
|
||||
dirpath2 string = "/testcopydir2"
|
||||
)
|
||||
|
||||
havelist1 := []string{
|
||||
"t1.txt",
|
||||
"t2.txt",
|
||||
}
|
||||
|
||||
createDir(dirpath1)
|
||||
for _, v := range havelist1 {
|
||||
createTestFile(dirpath1+"/"+v, "")
|
||||
}
|
||||
defer delTestFiles(dirpath1)
|
||||
|
||||
yfolder := testpath() + dirpath1
|
||||
tofolder := testpath() + dirpath2
|
||||
|
||||
if gfile.IsDir(tofolder) {
|
||||
gtest.Assert(gfile.Remove(tofolder), nil)
|
||||
gtest.Assert(gfile.Remove(""), nil)
|
||||
}
|
||||
|
||||
gtest.Assert(gfile.CopyDir(yfolder, tofolder), nil)
|
||||
defer delTestFiles(tofolder)
|
||||
|
||||
// 检查复制后的旧文件夹是否真实存在
|
||||
gtest.Assert(gfile.IsDir(yfolder), true)
|
||||
|
||||
// 检查复制后的旧文件夹中的文件是否真实存在
|
||||
for _, v := range havelist1 {
|
||||
gtest.Assert(gfile.IsFile(yfolder+"/"+v), true)
|
||||
}
|
||||
|
||||
// 检查复制后的新文件夹是否真实存在
|
||||
gtest.Assert(gfile.IsDir(tofolder), true)
|
||||
|
||||
// 检查复制后的新文件夹中的文件是否真实存在
|
||||
for _, v := range havelist1 {
|
||||
gtest.Assert(gfile.IsFile(tofolder+"/"+v), true)
|
||||
}
|
||||
|
||||
gtest.Assert(gfile.Remove(tofolder), nil)
|
||||
gtest.Assert(gfile.Remove(""), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ var (
|
||||
}
|
||||
|
||||
// Priority tags for Map*/Struct* functions.
|
||||
structTagPriority = []string{gGCONV_TAG, "json"}
|
||||
structTagPriority = []string{gGCONV_TAG, "c", "json"}
|
||||
)
|
||||
|
||||
// Convert converts the variable <i> to the type <t>, the type <t> is specified by string.
|
||||
|
||||
@ -14,6 +14,46 @@ import (
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
)
|
||||
|
||||
// SliceInt is alias of Ints.
|
||||
func SliceInt(i interface{}) []int {
|
||||
return Ints(i)
|
||||
}
|
||||
|
||||
// SliceStr is alias of Strings.
|
||||
func SliceStr(i interface{}) []string {
|
||||
return Strings(i)
|
||||
}
|
||||
|
||||
// SliceAny is alias of Interfaces.
|
||||
func SliceAny(i interface{}) []interface{} {
|
||||
return Interfaces(i)
|
||||
}
|
||||
|
||||
// SliceFloat is alias of Floats.
|
||||
func SliceFloat(i interface{}) []float64 {
|
||||
return Floats(i)
|
||||
}
|
||||
|
||||
// SliceMap is alias of Maps.
|
||||
func SliceMap(i interface{}) []map[string]interface{} {
|
||||
return Maps(i)
|
||||
}
|
||||
|
||||
// SliceMapDeep is alias of MapsDeep.
|
||||
func SliceMapDeep(i interface{}) []map[string]interface{} {
|
||||
return MapsDeep(i)
|
||||
}
|
||||
|
||||
// SliceStruct is alias of Structs.
|
||||
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return Structs(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// SliceStructDeep is alias of StructsDeep.
|
||||
func SliceStructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return StructsDeep(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// Ints converts <i> to []int.
|
||||
func Ints(i interface{}) []int {
|
||||
if i == nil {
|
||||
@ -350,6 +390,26 @@ func Maps(i interface{}) []map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// MapsDeep converts <i> to []map[string]interface{} recursively.
|
||||
func MapsDeep(i interface{}) []map[string]interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]map[string]interface{}); ok {
|
||||
return r
|
||||
} else {
|
||||
array := Interfaces(i)
|
||||
if len(array) == 0 {
|
||||
return nil
|
||||
}
|
||||
list := make([]map[string]interface{}, len(array))
|
||||
for k, v := range array {
|
||||
list[k] = MapDeep(v)
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
// Structs converts any slice to given struct slice.
|
||||
func Structs(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return doStructs(params, pointer, false, mapping...)
|
||||
|
||||
@ -15,8 +15,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// 同时支持valid和gvalid标签,优先使用valid
|
||||
structTagPriority = []string{"valid", "gvalid"}
|
||||
// 同时支持gvalid、valid和v标签,优先使用gvalid
|
||||
structTagPriority = []string{"gvalid", "valid", "v"}
|
||||
)
|
||||
|
||||
// 校验struct对象属性,object参数也可以是一个指向对象的指针,返回值同CheckMap方法。
|
||||
|
||||
8
geg/database/gdb/mssql/config.toml
Normal file
8
geg/database/gdb/mssql/config.toml
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
[database]
|
||||
type = "mssql"
|
||||
host = "127.0.0.1"
|
||||
port = "1451"
|
||||
user = "sa"
|
||||
pass = "eno@123"
|
||||
name = "frpc"
|
||||
14
geg/database/gdb/mssql/gdb_all.go
Normal file
14
geg/database/gdb/mssql/gdb_all.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r, err := g.DB().GetAll(`SELECT TOP 10 * FROM KF_PatInfo_Emergency`)
|
||||
fmt.Println(err)
|
||||
g.Dump(r.ToList())
|
||||
}
|
||||
4
geg/database/gdb/mysql/config2.toml
Normal file
4
geg/database/gdb/mysql/config2.toml
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
link = "mysql:root:8692651@tcp(192.168.1.11:3306)/test"
|
||||
7
geg/database/gdb/mysql/config3.toml
Normal file
7
geg/database/gdb/mysql/config3.toml
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
[database.default]
|
||||
link = "mysql:root:8692651@tcp(192.168.1.11:3306)/test"
|
||||
[database.user]
|
||||
link = "mysql:root:8692651@tcp(192.168.1.11:3306)/test"
|
||||
21
geg/database/gdb/mysql/gdb_all.go
Normal file
21
geg/database/gdb/mysql/gdb_all.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
// 开启调试模式,以便于记录所有执行的SQL
|
||||
db.SetDebug(true)
|
||||
|
||||
r, e := db.Table("test").OrderBy("id asc").All()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
if r != nil {
|
||||
fmt.Println(r.ToList())
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Config().AddPath("/home/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/geg/frame")
|
||||
if r, err := g.DB().Table("user").Where("uid=?", 1).One(); err == nil {
|
||||
fmt.Println(r["uid"].Int())
|
||||
fmt.Println(r["name"].String())
|
||||
|
||||
16
geg/database/gdb/mysql/gdb_config2.go
Normal file
16
geg/database/gdb/mysql/gdb_config2.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Config().SetFileName("config2.toml")
|
||||
if r, err := g.DB().Table("user").Where("uid=?", 1).One(); err == nil {
|
||||
fmt.Println(r["uid"].Int())
|
||||
fmt.Println(r["name"].String())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
23
geg/database/gdb/mysql/gdb_config3.go
Normal file
23
geg/database/gdb/mysql/gdb_config3.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Config().SetFileName("config3.toml")
|
||||
if r, err := g.DB().Table("user").Where("uid=?", 1).One(); err == nil {
|
||||
fmt.Println(r["uid"].Int())
|
||||
fmt.Println(r["name"].String())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
if r, err := g.DB("user").Table("user").Where("uid=?", 1).One(); err == nil {
|
||||
fmt.Println(r["uid"].Int())
|
||||
fmt.Println(r["name"].String())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
@ -2,25 +2,19 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Uid int
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
if r, err := g.DB().Table("user").Where("uid=?", 1).One(); r != nil {
|
||||
u := new(User)
|
||||
if err := r.ToStruct(u); err == nil {
|
||||
fmt.Println(" uid:", u.Uid)
|
||||
fmt.Println("name:", u.Name)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
v := math.MaxUint16
|
||||
//v := []byte{255, 127}
|
||||
//ve := gbinary.Encode(v)
|
||||
//ve1 := gbinary.BeEncodeByLength(len(ve), v)
|
||||
//fmt.Println(ve)
|
||||
//fmt.Println(ve1)
|
||||
|
||||
//fmt.Println(gbinary.LeDecodeToInt(gbinary.LeEncode(v)))
|
||||
fmt.Println(gbinary.BeDecodeToInt(gbinary.BeEncode(v)))
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.7.2"
|
||||
const VERSION = "v1.7.3"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user