Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei

This commit is contained in:
564104865
2021-11-07 16:05:17 +08:00
15 changed files with 2892 additions and 150 deletions

View File

@ -0,0 +1,709 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package garray_test
import (
"fmt"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
)
func ExampleIntArray_Walk() {
var array garray.IntArray
tables := g.SliceInt{10, 20}
prefix := 99
array.Append(tables...)
// Add prefix for given table names.
array.Walk(func(value int) int {
return prefix + value
})
fmt.Println(array.Slice())
// Output:
// [109 119]
}
func ExampleNewIntArray() {
s := garray.NewIntArray()
s.Append(10)
s.Append(20)
s.Append(15)
s.Append(30)
fmt.Println(s.Slice())
// Output:
// [10 20 15 30]
}
func ExampleNewIntArraySize() {
s := garray.NewIntArraySize(3, 5)
s.Set(0, 10)
s.Set(1, 20)
s.Set(2, 15)
s.Set(3, 30)
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
// Output:
// [10 20 15] 3 5
}
func ExampleNewIntArrayFrom() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
// Output:
// [10 20 15 30] 4 4
}
func ExampleNewIntArrayFromCopy() {
s := garray.NewIntArrayFromCopy(g.SliceInt{10, 20, 15, 30})
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
// Output:
// [10 20 15 30] 4 4
}
func ExampleIntArray_At() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
sAt := s.At(2)
fmt.Println(sAt)
// Output:
// 15
}
func ExampleIntArray_Get() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
sGet, sBool := s.Get(3)
fmt.Println(sGet, sBool)
// Output:
// 30 true
}
func ExampleIntArray_Set() {
s := garray.NewIntArraySize(3, 5)
s.Set(0, 10)
s.Set(1, 20)
s.Set(2, 15)
s.Set(3, 30)
fmt.Println(s.Slice())
// Output:
// [10 20 15]
}
func ExampleIntArray_SetArray() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s.Slice())
// Output:
// [10 20 15 30]
}
func ExampleIntArray_Replace() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s.Slice())
s.Replace(g.SliceInt{12, 13})
fmt.Println(s.Slice())
// Output:
// [10 20 15 30]
// [12 13 15 30]
}
func ExampleIntArray_Sum() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
a := s.Sum()
fmt.Println(a)
// Output:
// 75
}
func ExampleIntArray_Sort() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
a := s.Sort()
fmt.Println(a)
// Output:
// [10,15,20,30]
}
func ExampleIntArray_SortFunc() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.SortFunc(func(v1, v2 int) bool {
//fmt.Println(v1,v2)
return v1 > v2
})
fmt.Println(s)
s.SortFunc(func(v1, v2 int) bool {
return v1 < v2
})
fmt.Println(s)
// Output:
// [10,20,15,30]
// [30,20,15,10]
// [10,15,20,30]
}
func ExampleIntArray_InsertBefore() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
s.InsertBefore(1, 99)
fmt.Println(s.Slice())
// Output:
// [10 99 20 15 30]
}
func ExampleIntArray_InsertAfter() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
s.InsertAfter(1, 99)
fmt.Println(s.Slice())
// Output:
// [10 20 99 15 30]
}
func ExampleIntArray_Remove() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.Remove(1)
fmt.Println(s.Slice())
// Output:
// [10,20,15,30]
// [10 15 30]
}
func ExampleIntArray_RemoveValue() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.RemoveValue(20)
fmt.Println(s.Slice())
// Output:
// [10,20,15,30]
// [10 15 30]
}
func ExampleIntArray_PushLeft() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.PushLeft(96, 97, 98, 99)
fmt.Println(s.Slice())
// Output:
// [10,20,15,30]
// [96 97 98 99 10 20 15 30]
}
func ExampleIntArray_PushRight() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.PushRight(96, 97, 98, 99)
fmt.Println(s.Slice())
// Output:
// [10,20,15,30]
// [10 20 15 30 96 97 98 99]
}
func ExampleIntArray_PopLeft() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.PopLeft()
fmt.Println(s.Slice())
// Output:
// [10,20,15,30]
// [20 15 30]
}
func ExampleIntArray_PopRight() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30})
fmt.Println(s)
s.PopRight()
fmt.Println(s.Slice())
// Output:
// [10,20,15,30]
// [10 20 15]
}
func ExampleIntArray_PopRand() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60, 70})
fmt.Println(s)
r, _ := s.PopRand()
fmt.Println(s)
fmt.Println(r)
// May Output:
// [10,20,15,30,40,50,60,70]
// [10,20,15,30,40,60,70]
// 50
}
func ExampleIntArray_PopRands() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.PopRands(2)
fmt.Println(s)
fmt.Println(r)
// May Output:
// [10,20,15,30,40,50,60]
// [10,20,15,30,40]
// [50 60]
}
func ExampleIntArray_PopLefts() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.PopLefts(2)
fmt.Println(s)
fmt.Println(r)
// Output:
// [10,20,15,30,40,50,60]
// [15,30,40,50,60]
// [10 20]
}
func ExampleIntArray_PopRights() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.PopRights(2)
fmt.Println(s)
fmt.Println(r)
// Output:
// [10,20,15,30,40,50,60]
// [10,20,15,30,40]
// [50 60]
}
func ExampleIntArray_Range() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.Range(2, 5)
fmt.Println(r)
// Output:
// [10,20,15,30,40,50,60]
// [15 30 40]
}
func ExampleIntArray_SubSlice() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.SubSlice(3, 4)
fmt.Println(r)
// Output:
// [10,20,15,30,40,50,60]
// [30 40 50 60]
}
func ExampleIntArray_Append() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
s.Append(96, 97, 98)
fmt.Println(s)
// Output:
// [10,20,15,30,40,50,60]
// [10,20,15,30,40,50,60,96,97,98]
}
func ExampleIntArray_Len() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Len())
// Output:
// [10,20,15,30,40,50,60]
// 7
}
func ExampleIntArray_Slice() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s.Slice())
// Output:
// [10 20 15 30 40 50 60]
}
func ExampleIntArray_Interfaces() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
r := s.Interfaces()
fmt.Println(r)
// Output:
// [10 20 15 30 40 50 60]
}
func ExampleIntArray_Clone() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.Clone()
fmt.Println(r)
// Output:
// [10,20,15,30,40,50,60]
// [10,20,15,30,40,50,60]
}
func ExampleIntArray_Clear() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Clear())
fmt.Println(s)
// Output:
// [10,20,15,30,40,50,60]
// []
// []
}
func ExampleIntArray_Contains() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s.Contains(20))
fmt.Println(s.Contains(21))
// Output:
// true
// false
}
func ExampleIntArray_Search() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s.Search(20))
fmt.Println(s.Search(21))
// Output:
// 1
// -1
}
func ExampleIntArray_Unique() {
s := garray.NewIntArray()
s.SetArray(g.SliceInt{10, 20, 15, 15, 20, 50, 60})
fmt.Println(s)
fmt.Println(s.Unique())
// Output:
// [10,20,15,15,20,50,60]
// [10,20,15,50,60]
}
func ExampleIntArray_LockFunc() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
s.LockFunc(func(array []int) {
for i := 0; i < len(array)-1; i++ {
fmt.Println(array[i])
}
})
// Output:
// 10
// 20
// 15
// 30
// 40
// 50
}
func ExampleIntArray_RLockFunc() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
s.RLockFunc(func(array []int) {
for i := 0; i < len(array); i++ {
fmt.Println(array[i])
}
})
// Output:
// 10
// 20
// 15
// 30
// 40
// 50
// 60
}
func ExampleIntArray_Merge() {
s1 := garray.NewIntArray()
s2 := garray.NewIntArray()
s1.SetArray(g.SliceInt{10, 20, 15})
s2.SetArray(g.SliceInt{40, 50, 60})
fmt.Println(s1)
fmt.Println(s2)
s1.Merge(s2)
fmt.Println(s1)
// Output:
// [10,20,15]
// [40,50,60]
// [10,20,15,40,50,60]
}
func ExampleIntArray_Fill() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
s.Fill(2, 3, 99)
fmt.Println(s)
// Output:
// [10,20,15,30,40,50,60]
// [10,20,99,99,99,50,60]
}
func ExampleIntArray_Chunk() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
r := s.Chunk(3)
fmt.Println(r)
// Output:
// [10,20,15,30,40,50,60]
// [[10 20 15] [30 40 50] [60]]
}
func ExampleIntArray_Pad() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
s.Pad(8, 99)
fmt.Println(s)
s.Pad(-10, 89)
fmt.Println(s)
// Output:
// [10,20,15,30,40,50,60,99]
// [89,89,10,20,15,30,40,50,60,99]
}
func ExampleIntArray_Rand() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Rand())
// May Output:
// [10,20,15,30,40,50,60]
// 10 true
}
func ExampleIntArray_Rands() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Rands(3))
// May Output:
// [10,20,15,30,40,50,60]
// [20 50 20]
}
func ExampleIntArray_Shuffle() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Shuffle())
// May Output:
// [10,20,15,30,40,50,60]
// [10,40,15,50,20,60,30]
}
func ExampleIntArray_Reverse() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Reverse())
// Output:
// [10,20,15,30,40,50,60]
// [60,50,40,30,15,20,10]
}
func ExampleIntArray_Join() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.Join(","))
// Output:
// [10,20,15,30,40,50,60]
// 10,20,15,30,40,50,60
}
func ExampleIntArray_CountValues() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 15, 40, 40, 40})
fmt.Println(s.CountValues())
// Output:
// map[10:1 15:2 20:1 40:3]
}
func ExampleIntArray_Iterator() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
s.Iterator(func(k int, v int) bool {
fmt.Println(k, v)
return true
})
// Output:
// 0 10
// 1 20
// 2 15
// 3 30
// 4 40
// 5 50
// 6 60
}
func ExampleIntArray_IteratorAsc() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
s.IteratorAsc(func(k int, v int) bool {
fmt.Println(k, v)
return true
})
// Output:
// 0 10
// 1 20
// 2 15
// 3 30
// 4 40
// 5 50
// 6 60
}
func ExampleIntArray_IteratorDesc() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
s.IteratorDesc(func(k int, v int) bool {
fmt.Println(k, v)
return true
})
// Output:
// 6 60
// 5 50
// 4 40
// 3 30
// 2 15
// 1 20
// 0 10
}
func ExampleIntArray_String() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s)
fmt.Println(s.String())
// Output:
// [10,20,15,30,40,50,60]
// [10,20,15,30,40,50,60]
}
func ExampleIntArray_MarshalJSON() {
type Student struct {
Id int
Name string
Scores garray.IntArray
}
var array garray.IntArray
array.SetArray(g.SliceInt{98, 97, 96})
s := Student{
Id: 1,
Name: "john",
Scores: array,
}
b, _ := json.Marshal(s)
fmt.Println(string(b))
// Output:
// {"Id":1,"Name":"john","Scores":[98,97,96]}
}
func ExampleIntArray_UnmarshalJSON() {
b := []byte(`{"Id":1,"Name":"john","Scores":[98,96,97]}`)
type Student struct {
Id int
Name string
Scores *garray.IntArray
}
s := Student{}
json.Unmarshal(b, &s)
fmt.Println(s)
// Output:
// {1 john [98,96,97]}
}
func ExampleIntArray_UnmarshalValue() {
type Student struct {
Name string
Scores *garray.IntArray
}
var s *Student
gconv.Struct(g.Map{
"name": "john",
"scores": g.SliceInt{96, 98, 97},
}, &s)
fmt.Println(s)
// Output:
// &{john [96,98,97]}
}
func ExampleIntArray_FilterEmpty() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})
fmt.Println(s)
fmt.Println(s.FilterEmpty())
// Output:
// [10,40,50,0,0,0,60]
// [10,40,50,60]
}
func ExampleIntArray_IsEmpty() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
fmt.Println(s.IsEmpty())
s1 := garray.NewIntArray()
fmt.Println(s1.IsEmpty())
// Output:
// false
// true
}

View File

@ -0,0 +1,573 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package garray_test
import (
"fmt"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
)
func ExampleSortedStrArray_Walk() {
var array garray.SortedStrArray
tables := g.SliceStr{"user", "user_detail"}
prefix := "gf_"
array.Append(tables...)
// Add prefix for given table names.
array.Walk(func(value string) string {
return prefix + value
})
fmt.Println(array.Slice())
// Output:
// [gf_user gf_user_detail]
}
func ExampleNewSortedStrArray() {
s := garray.NewSortedStrArray()
s.Append("b")
s.Append("d")
s.Append("c")
s.Append("a")
fmt.Println(s.Slice())
// Output:
// [a b c d]
}
func ExampleNewSortedStrArraySize() {
s := garray.NewSortedStrArraySize(3)
s.SetArray([]string{"b", "d", "a", "c"})
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
// Output:
// [a b c d] 4 4
}
func ExampleNewStrArrayFromCopy() {
s := garray.NewSortedStrArrayFromCopy(g.SliceStr{"b", "d", "c", "a"})
fmt.Println(s.Slice())
// Output:
// [a b c d]
}
func ExampleSortedStrArray_At() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "d", "c", "a"})
sAt := s.At(2)
fmt.Println(s)
fmt.Println(sAt)
// Output:
// ["a","b","c","d"]
// c
}
func ExampleSortedStrArray_Get() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "d", "c", "a", "e"})
sGet, sBool := s.Get(3)
fmt.Println(s)
fmt.Println(sGet, sBool)
// Output:
// ["a","b","c","d","e"]
// d true
}
func ExampleSortedStrArray_SetArray() {
s := garray.NewSortedStrArray()
s.SetArray([]string{"b", "d", "a", "c"})
fmt.Println(s.Slice())
// Output:
// [a b c d]
}
func ExampleSortedStrArray_SetUnique() {
s := garray.NewSortedStrArray()
s.SetArray([]string{"b", "d", "a", "c", "c", "a"})
fmt.Println(s.SetUnique(true))
// Output:
// ["a","b","c","d"]
}
func ExampleSortedStrArray_Sum() {
s := garray.NewSortedStrArray()
s.SetArray([]string{"5", "3", "2"})
fmt.Println(s)
a := s.Sum()
fmt.Println(a)
// Output:
// ["2","3","5"]
// 10
}
func ExampleSortedStrArray_Sort() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"b", "d", "a", "c"})
fmt.Println(s)
a := s.Sort()
fmt.Println(a)
// Output:
// ["a","b","c","d"]
// ["a","b","c","d"]
}
func ExampleSortedStrArray_Remove() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
fmt.Println(s.Slice())
s.Remove(1)
fmt.Println(s.Slice())
// Output:
// [a b c d]
// [a c d]
}
func ExampleSortedStrArray_RemoveValue() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
fmt.Println(s.Slice())
s.RemoveValue("b")
fmt.Println(s.Slice())
// Output:
// [a b c d]
// [a c d]
}
func ExampleSortedStrArray_PopLeft() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
r, _ := s.PopLeft()
fmt.Println(r)
fmt.Println(s.Slice())
// Output:
// a
// [b c d]
}
func ExampleSortedStrArray_PopRight() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
fmt.Println(s.Slice())
r, _ := s.PopRight()
fmt.Println(r)
fmt.Println(s.Slice())
// Output:
// [a b c d]
// d
// [a b c]
}
func ExampleSortedStrArray_PopRights() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.PopRights(2)
fmt.Println(r)
fmt.Println(s)
// Output:
// [g h]
// ["a","b","c","d","e","f"]
}
func ExampleSortedStrArray_Rand() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r, _ := s.PopRand()
fmt.Println(r)
fmt.Println(s)
// May Output:
// b
// ["a","c","d","e","f","g","h"]
}
func ExampleSortedStrArray_PopRands() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.PopRands(2)
fmt.Println(r)
fmt.Println(s)
// May Output:
// [d a]
// ["b","c","e","f","g","h"]
}
func ExampleSortedStrArray_PopLefts() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.PopLefts(2)
fmt.Println(r)
fmt.Println(s)
// Output:
// [a b]
// ["c","d","e","f","g","h"]
}
func ExampleSortedStrArray_Range() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.Range(2, 5)
fmt.Println(r)
// Output:
// [c d e]
}
func ExampleSortedStrArray_SubSlice() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.SubSlice(3, 4)
fmt.Println(s.Slice())
fmt.Println(r)
// Output:
// [a b c d e f g h]
// [d e f g]
}
func ExampleSortedStrArray_Add() {
s := garray.NewSortedStrArray()
s.Add("b", "d", "c", "a")
fmt.Println(s)
// Output:
// ["a","b","c","d"]
}
func ExampleSortedStrArray_Append() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
fmt.Println(s)
s.Append("f", "e", "g")
fmt.Println(s)
// Output:
// ["a","b","c","d"]
// ["a","b","c","d","e","f","g"]
}
func ExampleSortedStrArray_Len() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s)
fmt.Println(s.Len())
// Output:
// ["a","b","c","d","e","f","g","h"]
// 8
}
func ExampleSortedStrArray_Slice() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s.Slice())
// Output:
// [a b c d e f g h]
}
func ExampleSortedStrArray_Interfaces() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.Interfaces()
fmt.Println(r)
// Output:
// [a b c d e f g h]
}
func ExampleSortedStrArray_Clone() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.Clone()
fmt.Println(r)
fmt.Println(s)
// Output:
// ["a","b","c","d","e","f","g","h"]
// ["a","b","c","d","e","f","g","h"]
}
func ExampleSortedStrArray_Clear() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s)
fmt.Println(s.Clear())
fmt.Println(s)
// Output:
// ["a","b","c","d","e","f","g","h"]
// []
// []
}
func ExampleSortedStrArray_Contains() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s.Contains("e"))
fmt.Println(s.Contains("E"))
fmt.Println(s.Contains("z"))
// Output:
// true
// false
// false
}
func ExampleSortedStrArray_ContainsI() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s)
fmt.Println(s.ContainsI("E"))
fmt.Println(s.ContainsI("z"))
// Output:
// ["a","b","c","d","e","f","g","h"]
// true
// false
}
func ExampleSortedStrArray_Search() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s)
fmt.Println(s.Search("e"))
fmt.Println(s.Search("E"))
fmt.Println(s.Search("z"))
// Output:
// ["a","b","c","d","e","f","g","h"]
// 4
// -1
// -1
}
func ExampleSortedStrArray_Unique() {
s := garray.NewSortedStrArray()
s.SetArray(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
fmt.Println(s)
fmt.Println(s.Unique())
// Output:
// ["a","b","c","c","c","d","d"]
// ["a","b","c","d"]
}
func ExampleSortedStrArray_LockFunc() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
s.LockFunc(func(array []string) {
array[len(array)-1] = "GF fans"
})
fmt.Println(s)
// Output:
// ["a","b","GF fans"]
}
func ExampleSortedStrArray_RLockFunc() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
s.RLockFunc(func(array []string) {
array[len(array)-1] = "GF fans"
fmt.Println(array[len(array)-1])
})
fmt.Println(s)
// Output:
// GF fans
// ["a","b","GF fans"]
}
func ExampleSortedStrArray_Merge() {
s1 := garray.NewSortedStrArray()
s2 := garray.NewSortedStrArray()
s1.SetArray(g.SliceStr{"b", "c", "a"})
s2.SetArray(g.SliceStr{"e", "d", "f"})
fmt.Println(s1)
fmt.Println(s2)
s1.Merge(s2)
fmt.Println(s1)
// Output:
// ["a","b","c"]
// ["d","e","f"]
// ["a","b","c","d","e","f"]
}
func ExampleSortedStrArray_Chunk() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
r := s.Chunk(3)
fmt.Println(r)
// Output:
// [[a b c] [d e f] [g h]]
}
func ExampleSortedStrArray_Rands() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s)
fmt.Println(s.Rands(3))
// May Output:
// ["a","b","c","d","e","f","g","h"]
// [h g c]
}
func ExampleSortedStrArray_Join() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
fmt.Println(s.Join(","))
// Output:
// a,b,c,d,e,f,g,h
}
func ExampleSortedStrArray_CountValues() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
fmt.Println(s.CountValues())
// Output:
// map[a:1 b:1 c:3 d:2]
}
func ExampleSortedStrArray_Iterator() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
s.Iterator(func(k int, v string) bool {
fmt.Println(k, v)
return true
})
// Output:
// 0 a
// 1 b
// 2 c
}
func ExampleSortedStrArray_IteratorAsc() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
s.IteratorAsc(func(k int, v string) bool {
fmt.Println(k, v)
return true
})
// Output:
// 0 a
// 1 b
// 2 c
}
func ExampleSortedStrArray_IteratorDesc() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
s.IteratorDesc(func(k int, v string) bool {
fmt.Println(k, v)
return true
})
// Output:
// 2 c
// 1 b
// 0 a
}
func ExampleSortedStrArray_String() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
fmt.Println(s.String())
// Output:
// ["a","b","c"]
}
func ExampleSortedStrArray_MarshalJSON() {
type Student struct {
ID int
Name string
Levels garray.SortedStrArray
}
r := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
s := Student{
ID: 1,
Name: "john",
Levels: *r,
}
b, _ := json.Marshal(s)
fmt.Println(string(b))
// Output:
// {"ID":1,"Name":"john","Levels":["a","b","c"]}
}
func ExampleSortedStrArray_UnmarshalJSON() {
b := []byte(`{"Id":1,"Name":"john","Lessons":["Math","English","Sport"]}`)
type Student struct {
Id int
Name string
Lessons *garray.StrArray
}
s := Student{}
json.Unmarshal(b, &s)
fmt.Println(s)
// Output:
// {1 john ["Math","English","Sport"]}
}
func ExampleSortedStrArray_UnmarshalValue() {
type Student struct {
Name string
Lessons *garray.StrArray
}
var s *Student
gconv.Struct(g.Map{
"name": "john",
"lessons": []byte(`["Math","English","Sport"]`),
}, &s)
fmt.Println(s)
var s1 *Student
gconv.Struct(g.Map{
"name": "john",
"lessons": g.SliceStr{"Math", "English", "Sport"},
}, &s1)
fmt.Println(s1)
// Output:
// &{john ["Math","English","Sport"]}
// &{john ["Math","English","Sport"]}
}
func ExampleSortedStrArray_FilterEmpty() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
fmt.Println(s)
fmt.Println(s.FilterEmpty())
// Output:
// ["","","","a","b","c","d"]
// ["a","b","c","d"]
}
func ExampleSortedStrArray_IsEmpty() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
fmt.Println(s.IsEmpty())
s1 := garray.NewSortedStrArray()
fmt.Println(s1.IsEmpty())
// Output:
// false
// true
}

View File

@ -7,17 +7,401 @@
package gset_test
import (
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
)
// New create and returns a new set, which contains un-repeated items.
// The parameter `safe` is used to specify whether using set in concurrent-safety,
// which is false in default.
func ExampleNewIntSet() {
intSet := gset.NewIntSet()
intSet.Add([]int{1, 2, 3}...)
fmt.Println(intSet.Slice())
// May Output:
// [2 1 3]
}
// NewIntSetFrom returns a new set from `items`.
func ExampleNewFrom() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
fmt.Println(intSet.Slice())
// May Output:
// [2 1 3]
}
// Add adds one or multiple items to the set.
func ExampleIntSet_Add() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
intSet.Add(1)
fmt.Println(intSet.Slice())
fmt.Println(intSet.AddIfNotExist(1))
// Mya Output:
// [1 2 3]
// false
}
// AddIfNotExist checks whether item exists in the set,
// it adds the item to set and returns true if it does not exists in the set,
// or else it does nothing and returns false.
func ExampleIntSet_AddIfNotExist() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
intSet.Add(1)
fmt.Println(intSet.Slice())
fmt.Println(intSet.AddIfNotExist(1))
// Mya Output:
// [1 2 3]
// false
}
// AddIfNotExistFunc checks whether item exists in the set,
// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,
// or else it does nothing and returns false.
// Note that, the function `f` is executed without writing lock.
func ExampleIntSet_AddIfNotExistFunc() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
intSet.Add(1)
fmt.Println(intSet.Slice())
fmt.Println(intSet.AddIfNotExistFunc(5, func() bool {
return true
}))
// May Output:
// [1 2 3]
// true
}
// AddIfNotExistFunc checks whether item exists in the set,
// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,
// or else it does nothing and returns false.
// Note that, the function `f` is executed without writing lock.
func ExampleIntSet_AddIfNotExistFuncLock() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
intSet.Add(1)
fmt.Println(intSet.Slice())
fmt.Println(intSet.AddIfNotExistFuncLock(4, func() bool {
return true
}))
// May Output:
// [1 2 3]
// true
}
// Clear deletes all items of the set.
func ExampleIntSet_Clear() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
fmt.Println(intSet.Size())
intSet.Clear()
fmt.Println(intSet.Size())
// Output:
// 3
// 0
}
// Complement returns a new set which is the complement from `set` to `full`.
// Which means, all the items in `newSet` are in `full` and not in `set`.
// It returns the difference between `full` and `set` if the given set `full` is not the full set of `set`.
func ExampleIntSet_Complement() {
intSet := gset.NewIntSetFrom([]int{1, 2, 3, 4, 5})
s := gset.NewIntSetFrom([]int{1, 2, 3})
fmt.Println(s.Complement(intSet).Slice())
// May Output:
// [4 5]
}
// Contains checks whether the set contains `item`.
func ExampleIntSet_Contains() {
var set gset.IntSet
set.Add(1)
fmt.Println(set.Contains(1))
fmt.Println(set.Contains(2))
var set1 gset.IntSet
set1.Add(1, 4, 5, 6, 7)
fmt.Println(set1.Contains(1))
var set2 gset.IntSet
set2.Add(1, 4, 5, 6, 7)
fmt.Println(set2.Contains(8))
// Output:
// true
// false
}
// Diff returns a new set which is the difference set from `set` to `other`.
// Which means, all the items in `newSet` are in `set` but not in `other`.
func ExampleIntSet_Diff() {
s1 := gset.NewIntSetFrom([]int{1, 2, 3})
s2 := gset.NewIntSetFrom([]int{1, 2, 3, 4})
fmt.Println(s2.Diff(s1).Slice())
// Output:
// [4]
}
// Equal checks whether the two sets equal.
func ExampleIntSet_Equal() {
s1 := gset.NewIntSetFrom([]int{1, 2, 3})
s2 := gset.NewIntSetFrom([]int{1, 2, 3, 4})
fmt.Println(s2.Equal(s1))
s3 := gset.NewIntSetFrom([]int{1, 2, 3})
s4 := gset.NewIntSetFrom([]int{1, 2, 3})
fmt.Println(s3.Equal(s4))
// Output:
// false
// true
}
// Intersect returns a new set which is the intersection from `set` to `other`.
// Which means, all the items in `newSet` are in `set` and also in `other`.
func ExampleIntSet_Intersect() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3}...)
var s2 gset.IntSet
s2.Add([]int{1, 2, 3, 4}...)
fmt.Println(s2.Intersect(s1).Slice())
// May Output:
// [1 2 3]
}
// IsSubsetOf checks whether the current set is a sub-set of `other`
func ExampleIntSet_IsSubsetOf() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
var s2 gset.IntSet
s2.Add([]int{1, 2, 4}...)
fmt.Println(s2.IsSubsetOf(s1))
// Output:
// true
}
// Iterator iterates the set readonly with given callback function `f`,
// if `f` returns true then continue iterating; or false to stop.
func ExampleIntSet_Iterator() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
s1.Iterator(func(v int) bool {
fmt.Println("Iterator", v)
return true
})
// May Output:
// Iterator 2
// Iterator 3
// Iterator 1
// Iterator 4
}
// Join joins items with a string `glue`.
func ExampleIntSet_Join() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
fmt.Println(s1.Join(","))
// May Output:
// 3,4,1,2
}
// LockFunc locks writing with callback function `f`.
func ExampleIntSet_LockFunc() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2}...)
s1.LockFunc(func(m map[int]struct{}) {
m[3] = struct{}{}
})
fmt.Println(s1.Slice())
// May Output
// [2 3 1]
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func ExampleIntSet_MarshalJSON() {
type Student struct {
Id int
Name string
Scores *gset.IntSet
}
s := Student{
Id: 1,
Name: "john",
Scores: gset.NewIntSetFrom([]int{100, 99, 98}),
}
b, _ := json.Marshal(s)
fmt.Println(string(b))
// May Output:
// {"Id":1,"Name":"john","Scores":[100,99,98]}
}
// Merge adds items from `others` sets into `set`.
func ExampleIntSet_Merge() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
s2 := gset.NewIntSet()
fmt.Println(s1.Merge(s2).Slice())
// May Output:
// [1 2 3 4]
}
// Pops randomly pops an item from set.
func ExampleIntSet_Pop() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
fmt.Println(s1.Pop())
// May Output:
// 1
}
// Pops randomly pops `size` items from set.
// It returns all items if size == -1.
func ExampleIntSet_Pops() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
for _, v := range s1.Pops(2) {
fmt.Println(v)
}
// May Output:
// 1
// 2
}
// RLockFunc locks reading with callback function `f`.
func ExampleIntSet_RLockFunc() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
s1.RLockFunc(func(m map[int]struct{}) {
fmt.Println(m)
})
// Output:
// map[1:{} 2:{} 3:{} 4:{}]
}
// Remove deletes `item` from set.
func ExampleIntSet_Remove() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
s1.Remove(1)
fmt.Println(s1.Slice())
// May Output:
// [3 4 2]
}
// Size returns the size of the set.
func ExampleIntSet_Size() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
fmt.Println(s1.Size())
// Output:
// 4
}
// Slice returns the a of items of the set as slice.
func ExampleIntSet_Slice() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
fmt.Println(s1.Slice())
// May Output:
// [1, 2, 3, 4]
}
// String returns items as a string, which implements like json.Marshal does.
func ExampleIntSet_String() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
fmt.Println(s1.String())
// May Output:
// [1,2,3,4]
}
// Sum sums items. Note: The items should be converted to int type,
// or you'd get a result that you unexpected.
func ExampleIntSet_Sum() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
fmt.Println(s1.Sum())
// Output:
// 10
}
// Union returns a new set which is the union of `set` and `other`.
// Which means, all the items in `newSet` are in `set` or in `other`.
func ExampleIntSet_Union() {
s1 := gset.NewIntSet()
s1.Add([]int{1, 2, 3, 4}...)
s2 := gset.NewIntSet()
s2.Add([]int{1, 2, 4}...)
fmt.Println(s1.Union(s2).Slice())
// May Output:
// [3 4 1 2]
}
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func ExampleIntSet_UnmarshalJSON() {
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
type Student struct {
Id int
Name string
Scores *gset.IntSet
}
s := Student{}
json.Unmarshal(b, &s)
fmt.Println(s)
// May Output:
// {1 john [100,99,98]}
}
// UnmarshalValue is an interface implement which sets any type of value for set.
func ExampleIntSet_UnmarshalValue() {
b := []byte(`{"Id":1,"Name":"john","Scores":100,99,98}`)
type Student struct {
Id int
Name string
Scores *gset.IntSet
}
s := Student{}
json.Unmarshal(b, &s)
fmt.Println(s)
// May Output:
// {1 john [100,99,98]}
}
// Walk applies a user supplied function `f` to every item of set.
func ExampleIntSet_Walk() {
var (
set gset.IntSet
names = g.SliceInt{1, 0}
delta = 10
)
set.Add(names...)
// Add prefix for given table names.
set.Walk(func(item int) int {
return delta + item
})
fmt.Println(set.Slice())
// May Output:
// [12 60]
}

View File

@ -1776,7 +1776,7 @@ CREATE TABLE %s (
t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[4])["uid"], 3)
t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[4])["score"], 5)
})
db.SetDebug(true)
// Result ScanList with struct elements and pointer attributes.
gtest.C(t, func(t *gtest.T) {
var users []Entity

View File

@ -0,0 +1,37 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package utils
import "fmt"
// ListToMapByKey converts `list` to a map[string]interface{} of which key is specified by `key`.
// Note that the item value may be type of slice.
func ListToMapByKey(list []map[string]interface{}, key string) map[string]interface{} {
var (
s = ""
m = make(map[string]interface{})
tempMap = make(map[string][]interface{})
hasMultiValues bool
)
for _, item := range list {
if k, ok := item[key]; ok {
s = fmt.Sprintf(`%v`, k)
tempMap[s] = append(tempMap[s], item)
if len(tempMap[s]) > 1 {
hasMultiValues = true
}
}
}
for k, v := range tempMap {
if hasMultiValues {
m[k] = v
} else {
m[k] = v[0]
}
}
return m
}

View File

@ -0,0 +1,26 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package utils
// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.
//
// Note that this function might be of low performance.
func MapPossibleItemByKey(data map[string]interface{}, key string) (foundKey string, foundValue interface{}) {
if len(data) == 0 {
return
}
if v, ok := data[key]; ok {
return key, v
}
// Loop checking.
for k, v := range data {
if EqualFoldWithoutChars(k, key) {
return k, v
}
}
return "", nil
}

View File

@ -0,0 +1,280 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gregex_test
import (
"bytes"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gregex"
"strings"
)
func ExampleIsMatch() {
patternStr := `\d+`
g.Dump(gregex.IsMatch(patternStr, []byte("hello 2022! hello gf!")))
g.Dump(gregex.IsMatch(patternStr, nil))
g.Dump(gregex.IsMatch(patternStr, []byte("hello gf!")))
// Output:
// true
// false
// false
}
func ExampleIsMatchString() {
patternStr := `\d+`
g.Dump(gregex.IsMatchString(patternStr, "hello 2022! hello gf!"))
g.Dump(gregex.IsMatchString(patternStr, "hello gf!"))
g.Dump(gregex.IsMatchString(patternStr, ""))
// Output:
// true
// false
// false
}
func ExampleMatch() {
patternStr := `(\w+)=(\w+)`
matchStr := "https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!"
// This method looks for the first match index
result, err := gregex.Match(patternStr, []byte(matchStr))
g.Dump(result)
g.Dump(err)
// Output:
// [
// "pageId=1114219",
// "pageId",
// "1114219",
// ]
// <nil>
}
func ExampleMatchString() {
patternStr := `(\w+)=(\w+)`
matchStr := "https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!"
// This method looks for the first match index
result, err := gregex.MatchString(patternStr, matchStr)
g.Dump(result)
g.Dump(err)
// Output:
// [
// "pageId=1114219",
// "pageId",
// "1114219",
// ]
// <nil>
}
func ExampleMatchAll() {
patternStr := `(\w+)=(\w+)`
matchStr := "https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!"
result, err := gregex.MatchAll(patternStr, []byte(matchStr))
g.Dump(result)
g.Dump(err)
// Output:
// [
// [
// "pageId=1114219",
// "pageId",
// "1114219",
// ],
// [
// "searchId=8QC5D1D2E",
// "searchId",
// "8QC5D1D2E",
// ],
// ]
// <nil>
}
func ExampleMatchAllString() {
patternStr := `(\w+)=(\w+)`
matchStr := "https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!"
result, err := gregex.MatchAllString(patternStr, matchStr)
g.Dump(result)
g.Dump(err)
// Output:
// [
// [
// "pageId=1114219",
// "pageId",
// "1114219",
// ],
// [
// "searchId=8QC5D1D2E",
// "searchId",
// "8QC5D1D2E",
// ],
// ]
// <nil>
}
func ExampleQuote() {
result := gregex.Quote(`[1-9]\d+`)
g.Dump(result)
// Output:
// "\[1-9\]\\d\+"
}
func ExampleReplace() {
var (
patternStr = `\d+`
str = "hello gf 2020!"
repStr = "2021"
result, err = gregex.Replace(patternStr, []byte(repStr), []byte(str))
)
g.Dump(err)
g.Dump(result)
// Output:
// <nil>
// "hello gf 2021!"
}
func ExampleReplaceFunc() {
// In contrast to [ExampleReplaceFunc]
// the result contains the `pattern' of all subpattern that use the matching function
result, err := gregex.ReplaceFuncMatch(`(\d+)~(\d+)`, []byte("hello gf 2018~2020!"), func(match [][]byte) []byte {
g.Dump(match)
match[2] = []byte("2021")
return bytes.Join(match[1:], []byte("~"))
})
g.Dump(result)
g.Dump(err)
// Output:
// [
// "2018~2020",
// "2018",
// "2020",
// ]
// "hello gf 2018~2021!"
// <nil>
}
func ExampleReplaceFuncMatch() {
var (
patternStr = `(\d+)~(\d+)`
str = "hello gf 2018~2020!"
)
// In contrast to [ExampleReplaceFunc]
// the result contains the `pattern' of all subpatterns that use the matching function
result, err := gregex.ReplaceFuncMatch(patternStr, []byte(str), func(match [][]byte) []byte {
g.Dump(match)
match[2] = []byte("2021")
return bytes.Join(match[1:], []byte("-"))
})
g.Dump(result)
g.Dump(err)
// Output:
// [
// "2018~2020",
// "2018",
// "2020",
// ]
// "hello gf 2018-2021!"
// <nil>
}
func ExampleReplaceString() {
patternStr := `\d+`
str := "hello gf 2020!"
replaceStr := "2021"
result, err := gregex.ReplaceString(patternStr, replaceStr, str)
g.Dump(result)
g.Dump(err)
// Output:
// "hello gf 2021!"
// <nil>
}
func ExampleReplaceStringFunc() {
replaceStrMap := map[string]string{
"2020": "2021",
}
// When the regular statement can match multiple results
// func can be used to further control the value that needs to be modified
result, err := gregex.ReplaceStringFunc(`\d+`, `hello gf 2018~2020!`, func(b string) string {
g.Dump(b)
if replaceStr, ok := replaceStrMap[b]; ok {
return replaceStr
}
return b
})
g.Dump(result)
g.Dump(err)
result, err = gregex.ReplaceStringFunc(`[a-z]*`, "gf@goframe.org", strings.ToUpper)
g.Dump(result)
g.Dump(err)
// Output:
// "2018"
// "2020"
// "hello gf 2018~2021!"
// <nil>
// "GF@GOFRAME.ORG"
// <nil>
}
func ExampleReplaceStringFuncMatch() {
var (
patternStr = `([A-Z])\w+`
str = "hello Golang 2018~2021!"
)
// In contrast to [ExampleReplaceFunc]
// the result contains the `pattern' of all subpatterns that use the matching function
result, err := gregex.ReplaceStringFuncMatch(patternStr, str, func(match []string) string {
g.Dump(match)
match[0] = "Gf"
return match[0]
})
g.Dump(result)
g.Dump(err)
// Output:
// [
// "Golang",
// "G",
// ]
// "hello Gf 2018~2021!"
// <nil>
}
func ExampleSplit() {
patternStr := `\d+`
str := "hello2020gf"
result := gregex.Split(patternStr, str)
g.Dump(result)
// Output:
// [
// "hello",
// "gf",
// ]
}
func ExampleValidate() {
// Valid match statement
g.Dump(gregex.Validate(`\d+`))
// Mismatched statement
g.Dump(gregex.Validate(`[a-9]\d+`))
// Output:
// <nil>
// {
// Code: "invalid character class range",
// Expr: "a-9",
// }
}

View File

@ -327,14 +327,7 @@ func Split(str, delimiter string) []string {
// and calls Trim to every element of this array. It ignores the elements
// which are empty after Trim.
func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
array := make([]string, 0)
for _, v := range strings.Split(str, delimiter) {
v = Trim(v, characterMask...)
if v != "" {
array = append(array, v)
}
}
return array
return utils.SplitAndTrim(str, delimiter, characterMask...)
}
// Join concatenates the elements of `array` to create a single string. The separator string

View File

@ -7,8 +7,11 @@
package gconv
import (
"database/sql"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/structs"
"github.com/gogf/gf/v2/internal/utils"
"reflect"
)
@ -38,7 +41,18 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
}
pointerKind = pointerType.Kind()
if pointerKind != reflect.Ptr {
return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got type: %v", pointerKind)
if pointerValue.CanAddr() {
pointerValue = pointerValue.Addr()
pointerType = pointerValue.Type()
pointerKind = pointerType.Kind()
} else {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
"params should be type of pointer, but got type: %v",
pointerType,
)
}
}
// Direct assignment checks!
var (
@ -94,3 +108,410 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
return doStruct(params, pointer, keyToAttributeNameMapping, "")
}
}
// ScanList converts `structSlice` to struct slice which contains other complex struct attributes.
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
//
// Usage example 1: Normal attribute struct relation:
// type EntityUser struct {
// Uid int
// Name string
// }
// type EntityUserDetail struct {
// Uid int
// Address string
// }
// type EntityUserScores struct {
// Id int
// Uid int
// Score int
// Course string
// }
// type Entity struct {
// User *EntityUser
// UserDetail *EntityUserDetail
// UserScores []*EntityUserScores
// }
// var users []*Entity
// ScanList(records, &users, "User")
// ScanList(records, &users, "User", "uid")
// ScanList(records, &users, "UserDetail", "User", "uid:Uid")
// ScanList(records, &users, "UserScores", "User", "uid:Uid")
// ScanList(records, &users, "UserScores", "User", "uid")
//
//
// Usage example 2: Embedded attribute struct relation:
// type EntityUser struct {
// Uid int
// Name string
// }
// type EntityUserDetail struct {
// Uid int
// Address string
// }
// type EntityUserScores struct {
// Id int
// Uid int
// Score int
// }
// type Entity struct {
// EntityUser
// UserDetail EntityUserDetail
// UserScores []EntityUserScores
// }
//
// var users []*Entity
// ScanList(records, &users)
// ScanList(records, &users, "UserDetail", "uid")
// ScanList(records, &users, "UserScores", "uid")
//
//
// The parameters "User/UserDetail/UserScores" in the example codes specify the target attribute struct
// that current result will be bound to.
//
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
// struct attribute name - not the attribute name of the bound to target. In the example codes, it's attribute
// name "Uid" of "User" of entity "Entity". It automatically calculates the HasOne/HasMany relationship with
// given `relation` parameter.
//
// See the example or unit testing cases for clear understanding for this function.
func ScanList(structSlice interface{}, structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
var (
relationAttrName string
relationFields string
)
switch len(relationAttrNameAndFields) {
case 2:
relationAttrName = relationAttrNameAndFields[0]
relationFields = relationAttrNameAndFields[1]
case 1:
relationFields = relationAttrNameAndFields[0]
}
return doScanList(structSlice, structSlicePointer, bindToAttrName, relationAttrName, relationFields)
}
// doScanList converts `structSlice` to struct slice which contains other complex struct attributes recursively.
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
func doScanList(structSlice interface{}, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string) (err error) {
var (
maps = Maps(structSlice)
)
if len(maps) == 0 {
return nil
}
// Necessary checks for parameters.
if bindToAttrName == "" {
return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
}
if relationAttrName == "." {
relationAttrName = ""
}
var (
reflectValue = reflect.ValueOf(structSlicePointer)
reflectKind = reflectValue.Kind()
)
if reflectKind == reflect.Interface {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
if reflectKind != reflect.Ptr {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
reflectKind,
)
}
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
if reflectKind != reflect.Slice && reflectKind != reflect.Array {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
reflectKind,
)
}
length := len(maps)
if length == 0 {
// The pointed slice is not empty.
if reflectValue.Len() > 0 {
// It here checks if it has struct item, which is already initialized.
// It then returns error to warn the developer its empty and no conversion.
if v := reflectValue.Index(0); v.Kind() != reflect.Ptr {
return sql.ErrNoRows
}
}
// Do nothing for empty struct slice.
return nil
}
var (
arrayValue reflect.Value // Like: []*Entity
arrayItemType reflect.Type // Like: *Entity
reflectType = reflect.TypeOf(structSlicePointer)
)
if reflectValue.Len() > 0 {
arrayValue = reflectValue
} else {
arrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)
}
// Slice element item.
arrayItemType = arrayValue.Index(0).Type()
// Relation variables.
var (
relationDataMap map[string]interface{}
relationFromFieldName string // Eg: relationKV: id:uid -> id
relationBindToFieldName string // Eg: relationKV: id:uid -> uid
)
if len(relationFields) > 0 {
// The relation key string of table filed name and attribute name
// can be joined with char '=' or ':'.
array := utils.SplitAndTrim(relationFields, "=")
if len(array) == 1 {
// Compatible with old splitting char ':'.
array = utils.SplitAndTrim(relationFields, ":")
}
if len(array) == 1 {
// The relation names are the same.
array = []string{relationFields, relationFields}
}
if len(array) == 2 {
// Defined table field to relation attribute name.
// Like:
// uid:Uid
// uid:UserId
relationFromFieldName = array[0]
relationBindToFieldName = array[1]
if key, _ := utils.MapPossibleItemByKey(maps[0], relationFromFieldName); key == "" {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot find possible related table field name "%s" from given relation fields "%s"`,
relationFromFieldName,
relationFields,
)
} else {
relationFromFieldName = key
}
} else {
return gerror.NewCode(
gcode.CodeInvalidParameter,
`parameter relationKV should be format of "ResultFieldName:BindToAttrName"`,
)
}
if relationFromFieldName != "" {
// Note that the value might be type of slice.
relationDataMap = utils.ListToMapByKey(maps, relationFromFieldName)
}
if len(relationDataMap) == 0 {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot find the relation data map, maybe invalid relation fields given "%v"`,
relationFields,
)
}
}
// Bind to target attribute.
var (
ok bool
bindToAttrValue reflect.Value
bindToAttrKind reflect.Kind
bindToAttrType reflect.Type
bindToAttrField reflect.StructField
)
if arrayItemType.Kind() == reflect.Ptr {
if bindToAttrField, ok = arrayItemType.Elem().FieldByName(bindToAttrName); !ok {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
bindToAttrName,
)
}
} else {
if bindToAttrField, ok = arrayItemType.FieldByName(bindToAttrName); !ok {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
bindToAttrName,
)
}
}
bindToAttrType = bindToAttrField.Type
bindToAttrKind = bindToAttrType.Kind()
// Bind to relation conditions.
var (
relationFromAttrValue reflect.Value
relationFromAttrField reflect.Value
relationBindToFieldNameChecked bool
)
for i := 0; i < arrayValue.Len(); i++ {
arrayElemValue := arrayValue.Index(i)
// The FieldByName should be called on non-pointer reflect.Value.
if arrayElemValue.Kind() == reflect.Ptr {
// Like: []*Entity
arrayElemValue = arrayElemValue.Elem()
if !arrayElemValue.IsValid() {
// The element is nil, then create one and set it to the slice.
// The "reflect.New(itemType.Elem())" creates a new element and returns the address of it.
// For example:
// reflect.New(itemType.Elem()) => *Entity
// reflect.New(itemType.Elem()).Elem() => Entity
arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
arrayValue.Index(i).Set(arrayElemValue.Addr())
}
} else {
// Like: []Entity
}
bindToAttrValue = arrayElemValue.FieldByName(bindToAttrName)
if relationAttrName != "" {
// Attribute value of current slice element.
relationFromAttrValue = arrayElemValue.FieldByName(relationAttrName)
if relationFromAttrValue.Kind() == reflect.Ptr {
relationFromAttrValue = relationFromAttrValue.Elem()
}
} else {
// Current slice element.
relationFromAttrValue = arrayElemValue
}
if len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
}
// Check and find possible bind to attribute name.
if relationFields != "" && !relationBindToFieldNameChecked {
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
if !relationFromAttrField.IsValid() {
var (
filedMap, _ = structs.FieldMap(structs.FieldMapInput{
Pointer: relationFromAttrValue,
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
})
)
if key, _ := utils.MapPossibleItemByKey(Map(filedMap), relationBindToFieldName); key == "" {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot find possible related attribute name "%s" from given relation fields "%s"`,
relationBindToFieldName,
relationFields,
)
} else {
relationBindToFieldName = key
}
}
relationBindToFieldNameChecked = true
}
switch bindToAttrKind {
case reflect.Array, reflect.Slice:
if len(relationDataMap) > 0 {
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
if relationFromAttrField.IsValid() {
//results := make(Result, 0)
results := make([]interface{}, 0)
for _, v := range SliceAny(relationDataMap[String(relationFromAttrField.Interface())]) {
item := v
results = append(results, item)
}
if err = Structs(results, bindToAttrValue.Addr()); err != nil {
return err
}
} else {
// Maybe the attribute does not exist yet.
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
}
} else {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`relationKey should not be empty as field "%s" is slice`,
bindToAttrName,
)
}
case reflect.Ptr:
var element reflect.Value
if bindToAttrValue.IsNil() {
element = reflect.New(bindToAttrType.Elem()).Elem()
} else {
element = bindToAttrValue.Elem()
}
if len(relationDataMap) > 0 {
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
if relationFromAttrField.IsValid() {
v := relationDataMap[String(relationFromAttrField.Interface())]
if v == nil {
// There's no relational data.
continue
}
if utils.IsSlice(v) {
if err = Struct(SliceAny(v)[0], element); err != nil {
return err
}
} else {
if err = Struct(v, element); err != nil {
return err
}
}
} else {
// Maybe the attribute does not exist yet.
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
}
} else {
if i >= len(maps) {
// There's no relational data.
continue
}
v := maps[i]
if v == nil {
// There's no relational data.
continue
}
if err = Struct(v, element); err != nil {
return err
}
}
bindToAttrValue.Set(element.Addr())
case reflect.Struct:
if len(relationDataMap) > 0 {
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
if relationFromAttrField.IsValid() {
relationDataItem := relationDataMap[String(relationFromAttrField.Interface())]
if relationDataItem == nil {
// There's no relational data.
continue
}
if utils.IsSlice(relationDataItem) {
if err = Struct(SliceAny(relationDataItem)[0], bindToAttrValue); err != nil {
return err
}
} else {
if err = Struct(relationDataItem, bindToAttrValue); err != nil {
return err
}
}
} else {
// Maybe the attribute does not exist yet.
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
}
} else {
if i >= len(maps) {
// There's no relational data.
continue
}
relationDataItem := maps[i]
if relationDataItem == nil {
// There's no relational data.
continue
}
if err = Struct(relationDataItem, bindToAttrValue); err != nil {
return err
}
}
default:
return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())
}
}
reflect.ValueOf(structSlicePointer).Elem().Set(arrayValue)
return nil
}

View File

@ -319,3 +319,285 @@ func Test_Scan_SameType_Just_Assign(t *testing.T) {
t.Assert(*m1["int"], *m2["int"])
})
}
func Test_ScanList_Basic(t *testing.T) {
// Struct attribute.
gtest.C(t, func(t *gtest.T) {
type EntityUser struct {
Uid int
Name string
}
type EntityUserDetail struct {
Uid int
Address string
}
type EntityUserScores struct {
Id int
Uid int
Score int
}
type Entity struct {
User EntityUser
UserDetail EntityUserDetail
UserScores []EntityUserScores
}
var (
err error
entities []Entity
entityUsers = []EntityUser{
{Uid: 1, Name: "name1"},
{Uid: 2, Name: "name2"},
{Uid: 3, Name: "name3"},
}
userDetails = []EntityUserDetail{
{Uid: 1, Address: "address1"},
{Uid: 2, Address: "address2"},
}
userScores = []EntityUserScores{
{Id: 10, Uid: 1, Score: 100},
{Id: 11, Uid: 1, Score: 60},
{Id: 20, Uid: 2, Score: 99},
}
)
err = gconv.ScanList(entityUsers, &entities, "User")
t.AssertNil(err)
err = gconv.ScanList(userDetails, &entities, "UserDetail", "User", "uid")
t.AssertNil(err)
err = gconv.ScanList(userScores, &entities, "UserScores", "User", "uid")
t.AssertNil(err)
t.Assert(len(entities), 3)
t.Assert(entities[0].User, entityUsers[0])
t.Assert(entities[1].User, entityUsers[1])
t.Assert(entities[2].User, entityUsers[2])
t.Assert(entities[0].UserDetail, userDetails[0])
t.Assert(entities[1].UserDetail, userDetails[1])
t.Assert(entities[2].UserDetail, EntityUserDetail{})
t.Assert(len(entities[0].UserScores), 2)
t.Assert(entities[0].UserScores[0], userScores[0])
t.Assert(entities[0].UserScores[1], userScores[1])
t.Assert(len(entities[1].UserScores), 1)
t.Assert(entities[1].UserScores[0], userScores[2])
t.Assert(len(entities[2].UserScores), 0)
})
// Pointer attribute.
gtest.C(t, func(t *gtest.T) {
type EntityUser struct {
Uid int
Name string
}
type EntityUserDetail struct {
Uid int
Address string
}
type EntityUserScores struct {
Id int
Uid int
Score int
}
type Entity struct {
User *EntityUser
UserDetail *EntityUserDetail
UserScores []*EntityUserScores
}
var (
err error
entities []*Entity
entityUsers = []*EntityUser{
{Uid: 1, Name: "name1"},
{Uid: 2, Name: "name2"},
{Uid: 3, Name: "name3"},
}
userDetails = []*EntityUserDetail{
{Uid: 1, Address: "address1"},
{Uid: 2, Address: "address2"},
}
userScores = []*EntityUserScores{
{Id: 10, Uid: 1, Score: 100},
{Id: 11, Uid: 1, Score: 60},
{Id: 20, Uid: 2, Score: 99},
}
)
err = gconv.ScanList(entityUsers, &entities, "User")
t.AssertNil(err)
err = gconv.ScanList(userDetails, &entities, "UserDetail", "User", "uid")
t.AssertNil(err)
err = gconv.ScanList(userScores, &entities, "UserScores", "User", "uid")
t.AssertNil(err)
t.Assert(len(entities), 3)
t.Assert(entities[0].User, entityUsers[0])
t.Assert(entities[1].User, entityUsers[1])
t.Assert(entities[2].User, entityUsers[2])
t.Assert(entities[0].UserDetail, userDetails[0])
t.Assert(entities[1].UserDetail, userDetails[1])
t.Assert(entities[2].UserDetail, nil)
t.Assert(len(entities[0].UserScores), 2)
t.Assert(entities[0].UserScores[0], userScores[0])
t.Assert(entities[0].UserScores[1], userScores[1])
t.Assert(len(entities[1].UserScores), 1)
t.Assert(entities[1].UserScores[0], userScores[2])
t.Assert(len(entities[2].UserScores), 0)
})
}
func Test_ScanList_Embedded(t *testing.T) {
// Struct attribute.
gtest.C(t, func(t *gtest.T) {
type EntityUser struct {
Uid int
Name string
}
type EntityUserDetail struct {
Uid int
Address string
}
type EntityUserScores struct {
Id int
Uid int
Score int
}
type Entity struct {
EntityUser
UserDetail EntityUserDetail
UserScores []EntityUserScores
}
var (
err error
entities []Entity
entityUsers = []EntityUser{
{Uid: 1, Name: "name1"},
{Uid: 2, Name: "name2"},
{Uid: 3, Name: "name3"},
}
userDetails = []EntityUserDetail{
{Uid: 1, Address: "address1"},
{Uid: 2, Address: "address2"},
}
userScores = []EntityUserScores{
{Id: 10, Uid: 1, Score: 100},
{Id: 11, Uid: 1, Score: 60},
{Id: 20, Uid: 2, Score: 99},
}
)
err = gconv.Scan(entityUsers, &entities)
t.AssertNil(err)
err = gconv.ScanList(userDetails, &entities, "UserDetail", "uid")
t.AssertNil(err)
err = gconv.ScanList(userScores, &entities, "UserScores", "uid")
t.AssertNil(err)
t.Assert(len(entities), 3)
t.Assert(entities[0].EntityUser, entityUsers[0])
t.Assert(entities[1].EntityUser, entityUsers[1])
t.Assert(entities[2].EntityUser, entityUsers[2])
t.Assert(entities[0].UserDetail, userDetails[0])
t.Assert(entities[1].UserDetail, userDetails[1])
t.Assert(entities[2].UserDetail, EntityUserDetail{})
t.Assert(len(entities[0].UserScores), 2)
t.Assert(entities[0].UserScores[0], userScores[0])
t.Assert(entities[0].UserScores[1], userScores[1])
t.Assert(len(entities[1].UserScores), 1)
t.Assert(entities[1].UserScores[0], userScores[2])
t.Assert(len(entities[2].UserScores), 0)
})
// Pointer attribute.
gtest.C(t, func(t *gtest.T) {
type EntityUser struct {
Uid int
Name string
}
type EntityUserDetail struct {
Uid int
Address string
}
type EntityUserScores struct {
Id int
Uid int
Score int
}
type Entity struct {
*EntityUser
UserDetail *EntityUserDetail
UserScores []*EntityUserScores
}
var (
err error
entities []Entity
entityUsers = []EntityUser{
{Uid: 1, Name: "name1"},
{Uid: 2, Name: "name2"},
{Uid: 3, Name: "name3"},
}
userDetails = []EntityUserDetail{
{Uid: 1, Address: "address1"},
{Uid: 2, Address: "address2"},
}
userScores = []EntityUserScores{
{Id: 10, Uid: 1, Score: 100},
{Id: 11, Uid: 1, Score: 60},
{Id: 20, Uid: 2, Score: 99},
}
)
err = gconv.Scan(entityUsers, &entities)
t.AssertNil(err)
err = gconv.ScanList(userDetails, &entities, "UserDetail", "uid")
t.AssertNil(err)
err = gconv.ScanList(userScores, &entities, "UserScores", "uid")
t.AssertNil(err)
t.Assert(len(entities), 3)
t.Assert(entities[0].EntityUser, entityUsers[0])
t.Assert(entities[1].EntityUser, entityUsers[1])
t.Assert(entities[2].EntityUser, entityUsers[2])
t.Assert(entities[0].UserDetail, userDetails[0])
t.Assert(entities[1].UserDetail, userDetails[1])
t.Assert(entities[2].UserDetail, nil)
t.Assert(len(entities[0].UserScores), 2)
t.Assert(entities[0].UserScores[0], userScores[0])
t.Assert(entities[0].UserScores[1], userScores[1])
t.Assert(len(entities[1].UserScores), 1)
t.Assert(entities[1].UserScores[0], userScores[2])
t.Assert(len(entities[2].UserScores), 0)
})
}

View File

@ -15,6 +15,16 @@ import (
"strings"
)
// iString is used for type assert api for String().
type iString interface {
String() string
}
// iMarshalJSON is the interface for custom Json marshaling.
type iMarshalJSON interface {
MarshalJSON() ([]byte, error)
}
// ExportOption specifies the behavior of function Export.
type ExportOption struct {
WithoutType bool // WithoutType specifies exported content has no type information.
@ -151,7 +161,7 @@ func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doE
"%s%v:%s",
newIndent,
mapKeyStr,
gstr.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
} else {
buffer.WriteString(fmt.Sprintf(
@ -159,7 +169,7 @@ func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doE
newIndent,
mapKey.Type().String(),
mapKeyStr,
gstr.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
}
doExport(reflectValue.MapIndex(mapKey).Interface(), newIndent, buffer, option)
@ -173,10 +183,31 @@ func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doE
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
})
if len(structFields) == 0 {
if option.WithoutType {
buffer.WriteString("{}")
var (
structContentStr = ""
attributeCountStr = "0"
)
if v, ok := value.(iString); ok {
structContentStr = v.String()
} else if v, ok := value.(iMarshalJSON); ok {
b, _ := v.MarshalJSON()
structContentStr = string(b)
}
if structContentStr == "" {
structContentStr = "{}"
} else {
buffer.WriteString(fmt.Sprintf("%s(0) {}", reflectTypeName))
structContentStr = fmt.Sprintf(`"%s"`, gstr.AddSlashes(structContentStr))
attributeCountStr = fmt.Sprintf(`%d`, len(structContentStr)-2)
}
if option.WithoutType {
buffer.WriteString(structContentStr)
} else {
buffer.WriteString(fmt.Sprintf(
"%s(%s) %s",
reflectTypeName,
attributeCountStr,
structContentStr,
))
}
return
}
@ -202,7 +233,7 @@ func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doE
"%s%s:%s",
newIndent,
field.Name(),
gstr.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
doExport(field.Value.Interface(), newIndent, buffer, option)
buffer.WriteString(",\n")

View File

@ -7,6 +7,7 @@
package gutil
import (
"github.com/gogf/gf/v2/internal/utils"
"reflect"
)
@ -130,3 +131,9 @@ func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) [
}
return values
}
// ListToMapByKey converts `list` to a map[string]interface{} of which key is specified by `key`.
// Note that the item value may be type of slice.
func ListToMapByKey(list []map[string]interface{}, key string) map[string]interface{} {
return utils.ListToMapByKey(list, key)
}

View File

@ -67,19 +67,7 @@ func MapMergeCopy(src ...map[string]interface{}) (copy map[string]interface{}) {
//
// Note that this function might be of low performance.
func MapPossibleItemByKey(data map[string]interface{}, key string) (foundKey string, foundValue interface{}) {
if len(data) == 0 {
return
}
if v, ok := data[key]; ok {
return key, v
}
// Loop checking.
for k, v := range data {
if utils.EqualFoldWithoutChars(k, key) {
return k, v
}
}
return "", nil
return utils.MapPossibleItemByKey(data, key)
}
// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.

View File

@ -0,0 +1,128 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gutil_test
import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
"testing"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/gutil"
)
func Test_Dump(t *testing.T) {
type CommonReq struct {
AppId int64 `json:"appId" v:"required" in:"path" des:"应用Id" sum:"应用Id Summary"`
ResourceId string `json:"resourceId" in:"query" des:"资源Id" sum:"资源Id Summary"`
}
type SetSpecInfo struct {
StorageType string `v:"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD" des:"StorageType"`
Shards int32 `des:"shards 分片数" sum:"Shards Summary"`
Params []string `des:"默认参数(json 串-ClickHouseParams)" sum:"Params Summary"`
}
type CreateResourceReq struct {
CommonReq
gmeta.Meta `path:"/CreateResourceReq" method:"POST" tags:"default" sum:"CreateResourceReq sum"`
Name string
CreatedAt *gtime.Time
SetMap map[string]*SetSpecInfo
SetSlice []SetSpecInfo
Handler ghttp.HandlerFunc
internal string
}
req := &CreateResourceReq{
CommonReq: CommonReq{
AppId: 12345678,
ResourceId: "tdchqy-xxx",
},
Name: "john",
CreatedAt: gtime.Now(),
SetMap: map[string]*SetSpecInfo{
"test1": {
StorageType: "ssd",
Shards: 2,
Params: []string{"a", "b", "c"},
},
"test2": {
StorageType: "hssd",
Shards: 10,
Params: []string{},
},
},
SetSlice: []SetSpecInfo{
{
StorageType: "hssd",
Shards: 10,
Params: []string{"h"},
},
},
}
gtest.C(t, func(t *gtest.T) {
gutil.Dump(map[int]int{
100: 100,
})
gutil.Dump(req)
})
}
func TestDumpWithType(t *testing.T) {
type CommonReq struct {
AppId int64 `json:"appId" v:"required" in:"path" des:"应用Id" sum:"应用Id Summary"`
ResourceId string `json:"resourceId" in:"query" des:"资源Id" sum:"资源Id Summary"`
}
type SetSpecInfo struct {
StorageType string `v:"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD" des:"StorageType"`
Shards int32 `des:"shards 分片数" sum:"Shards Summary"`
Params []string `des:"默认参数(json 串-ClickHouseParams)" sum:"Params Summary"`
}
type CreateResourceReq struct {
CommonReq
gmeta.Meta `path:"/CreateResourceReq" method:"POST" tags:"default" sum:"CreateResourceReq sum"`
Name string
CreatedAt *gtime.Time
SetMap map[string]*SetSpecInfo `v:"required" des:"配置Map"`
SetSlice []SetSpecInfo `v:"required" des:"配置Slice"`
Handler ghttp.HandlerFunc
internal string
}
req := &CreateResourceReq{
CommonReq: CommonReq{
AppId: 12345678,
ResourceId: "tdchqy-xxx",
},
Name: "john",
CreatedAt: gtime.Now(),
SetMap: map[string]*SetSpecInfo{
"test1": {
StorageType: "ssd",
Shards: 2,
Params: []string{"a", "b", "c"},
},
"test2": {
StorageType: "hssd",
Shards: 10,
Params: []string{},
},
},
SetSlice: []SetSpecInfo{
{
StorageType: "hssd",
Shards: 10,
Params: []string{"h"},
},
},
}
gtest.C(t, func(t *gtest.T) {
gutil.DumpWithType(map[int]int{
100: 100,
})
gutil.DumpWithType(req)
gutil.DumpWithType([][]byte{[]byte("hello")})
})
}

View File

@ -8,129 +8,12 @@ package gutil_test
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/gmeta"
"testing"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/gutil"
)
func Test_Dump(t *testing.T) {
type CommonReq struct {
AppId int64 `json:"appId" v:"required" in:"path" des:"应用Id" sum:"应用Id Summary"`
ResourceId string `json:"resourceId" in:"query" des:"资源Id" sum:"资源Id Summary"`
}
type SetSpecInfo struct {
StorageType string `v:"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD" des:"StorageType"`
Shards int32 `des:"shards 分片数" sum:"Shards Summary"`
Params []string `des:"默认参数(json 串-ClickHouseParams)" sum:"Params Summary"`
}
type CreateResourceReq struct {
CommonReq
gmeta.Meta `path:"/CreateResourceReq" method:"POST" tags:"default" sum:"CreateResourceReq sum"`
Name string `des:"实例名称"`
Product string `des:"业务类型"`
Region string `v:"required" des:"区域"`
SetMap map[string]*SetSpecInfo `v:"required" des:"配置Map"`
SetSlice []SetSpecInfo `v:"required" des:"配置Slice"`
Handler ghttp.HandlerFunc
internal string
}
req := &CreateResourceReq{
CommonReq: CommonReq{
AppId: 12345678,
ResourceId: "tdchqy-xxx",
},
Name: "john",
Product: "goframe",
Region: "cd",
SetMap: map[string]*SetSpecInfo{
"test1": {
StorageType: "ssd",
Shards: 2,
Params: []string{"a", "b", "c"},
},
"test2": {
StorageType: "hssd",
Shards: 10,
Params: []string{},
},
},
SetSlice: []SetSpecInfo{
{
StorageType: "hssd",
Shards: 10,
Params: []string{"h"},
},
},
}
gtest.C(t, func(t *gtest.T) {
gutil.Dump(map[int]int{
100: 100,
})
gutil.Dump(req)
})
}
func TestDumpWithType(t *testing.T) {
type CommonReq struct {
AppId int64 `json:"appId" v:"required" in:"path" des:"应用Id" sum:"应用Id Summary"`
ResourceId string `json:"resourceId" in:"query" des:"资源Id" sum:"资源Id Summary"`
}
type SetSpecInfo struct {
StorageType string `v:"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD" des:"StorageType"`
Shards int32 `des:"shards 分片数" sum:"Shards Summary"`
Params []string `des:"默认参数(json 串-ClickHouseParams)" sum:"Params Summary"`
}
type CreateResourceReq struct {
CommonReq
gmeta.Meta `path:"/CreateResourceReq" method:"POST" tags:"default" sum:"CreateResourceReq sum"`
Name string `des:"实例名称"`
Product string `des:"业务类型"`
Region string `v:"required" des:"区域"`
SetMap map[string]*SetSpecInfo `v:"required" des:"配置Map"`
SetSlice []SetSpecInfo `v:"required" des:"配置Slice"`
Handler ghttp.HandlerFunc
internal string
}
req := &CreateResourceReq{
CommonReq: CommonReq{
AppId: 12345678,
ResourceId: "tdchqy-xxx",
},
Name: "john",
Product: "goframe",
Region: "cd",
SetMap: map[string]*SetSpecInfo{
"test1": {
StorageType: "ssd",
Shards: 2,
Params: []string{"a", "b", "c"},
},
"test2": {
StorageType: "hssd",
Shards: 10,
Params: []string{},
},
},
SetSlice: []SetSpecInfo{
{
StorageType: "hssd",
Shards: 10,
Params: []string{"h"},
},
},
}
gtest.C(t, func(t *gtest.T) {
gutil.DumpWithType(map[int]int{
100: 100,
})
gutil.DumpWithType(req)
gutil.DumpWithType([][]byte{[]byte("hello")})
})
}
func Test_Try(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := `gutil Try test`