前言
写过 PHP 的同学都晓得 PHP 的数组 Array 十分好用,特地灵便 。
我在写 PHP 之前应用 Java 做安卓开发,在接触 PHP 的数组 Array 之后,直呼太香了!
而在学习 Go 基础知识的时候理解到 Go 的数组和 PHP 的数组并不一样;从肯定水平上讲,Go 的 slice 切片类型和 PHP 的数组 array 比拟像(不固定长度、援用类型、动静扩容等),然而在开发应用中远远不像 PHP 的 array 灵便。
初识 GoFrame
最近在应用基于 Go 语言的 GoFrame 框架撸我的项目,发现 GoFrame 封装的 garray 居然比 PHP 的 array 还要好用。
近期曾经更新了一系列 GoFrame 的文章,下文将 GoFrame 简称为 gf。
gf 框架有个特点,提供的组件根本都反对设置并发平安开关。 显然 PHP 是不反对并发平安开关的,PHP 的数组是并发平安的。PHP-FPM 是阻塞的单线程模型,PHP-FPM 每个过程里只有一个线程,一个过程同时只能服务一个客户端。
garray 特点简介
- garray 反对 int/string/interface{} 三种罕用的数据类型。
- garray 反对一般数组和排序数组,一般数组的构造体名称定义为 Array 格局,排序数组的构造体名称定义为 SortedArray 格局,如下:Array, intArray, StrArray,SortedArray, SortedIntArray, SortedStrArray
- 其中排序数组 SortedArray,须要给定排序比拟办法,在工具包 gutil 中也定义了很多 ComparatorXXX 的比拟办法,用起来很不便。当然也反对自定义排序形式。
根本应用
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
)
func main() {
// 创立并发平安的 int 型数组
a := garray.NewIntArray(true)
// 增加数组项
for i := 0; i < 10; i++ {a.Append(i)
}
// 打印后果:fmt.Println(a) //"[0,1,2,3,4,5,6,7,8,9]"
fmt.Println("数组长度:", a.Len())
fmt.Println("数组的值:", a.Slice())
fmt.Println((a.Get(5))) // 依据索引取值 返回值和是否取到了值 5 true
// 在指定索引前后插入值
_ = a.InsertAfter(9, 10)
_ = a.InsertBefore(0, -1)
fmt.Println(a.Slice())
// 搜寻数据项,返回对应的索引
fmt.Println("搜寻值,返回对应索引:", a.Search(5))
// 删除
a.Remove(0)
fmt.Println(a.Slice())
// 并发平安 写锁操作
a.LockFunc(func(array []int) {
// 将最初一项的值改为 100
array[len(array)-1] = 100
})
fmt.Println(a) //"[0,1,2,3,4,5,6,7,8,9,100]"
// 并发平安 读锁操作
a.RLockFunc(func(array []int) {fmt.Println(array[len(array)-1]) //100
})
// 清空数组
a.Clear()
fmt.Println("清空数组之后:", a.Slice())
}
打印后果
数组出栈
- 数组出栈应用 Pop* 关键字
- 数组能够按程序出栈,而 gf 提供的另外一个数据类型 gmap 的 pop* 办法是随机出栈 (关注我,会在后续的文章中更新阐明)
- garray 中随机出栈,咱们能够应用 rand() 或者 popRand()
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
// 数组出栈 pop 数组能够按程序出栈 map 的 pop 是随机出栈
func main() {a := garray.NewFrom([]interface{}{1, 2, 3, 4, 5, 6})
fmt.Println(a.PopLeft())
fmt.Println(a.PopLefts(2))
fmt.Println(a.PopRight())
fmt.Println(a.PopRights(2))
fmt.Println(a) // 全副出栈后 数组为空
/**
打印后果:1 true
[2 3]
6 true
[4 5]
[]
*/
// 有什么方法能像 map 一样随机出栈呢?在 garray 中咱们应用 rand() 或者 popRand()
a1 := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})
fmt.Println("----------")
fmt.Println(a1.Rand()) // 随机取值
fmt.Println(a1.PopRands(2)) // 随机出栈
fmt.Println(a1)
}
蕴含判断
- 留神:Contains() 是辨别大小写
- 空值过滤应用:FilterEmpty
- nil 过滤应用:FilterNil
package main
import (
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
// 蕴含 contains 辨别大小写
func main() {
var a garray.Array
a.Append("a")
g.Dump(a.Contains("a")) //true
g.Dump(a.Contains("A")) //false
// 空值过滤
a1 := garray.NewFrom([]interface{}{0, 1, "2", nil, false, g.Slice{}, "王中阳"})
a2 := garray.NewFrom([]interface{}{0, 1, "2", nil, false, g.Slice{}, "王中阳"})
g.Dump("empty 过滤:", a1.FilterEmpty()) //empty 过滤:"[1,2," 王中阳 "]"
g.Dump("nil 过滤:", a2.FilterNil()) //nil 过滤:"[0,1,2,"false","[]"," 王中阳 "]"
a3 := garray.NewFrom([]interface{}{1, 2, 3, 4, 5, 6, 7})
g.Dump("数组翻转:", a3.Reverse())
g.Dump("数组随机排序:", a3.Shuffle())
}
打印后果
排序数组
- 咱们能够自定义 NewSortedArray 的排序规定,以实现是升序数组还是降序数组;
- 排序数组还有唯一性校验的性能:garray.SetUnique(true)
- gf 框架的 gutil 工具包定义好了罕用的排序规定
package main
import (
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gutil"
)
// 咱们能够自定义 NewSortedArray 的排序规定,以实现是升序数组还是降序数组;排序数组还有唯一性校验的性能
func main() {
// 自定义排序数组:降序排列
a := garray.NewSortedArray(func(a, b interface{}) int {if a.(int) < b.(int) {return 1}
if a.(int) > b.(int) {return -1}
return 0
})
// 排序规格能够应用 gutil 中定义好的
a.Add(2) // 数组的赋值用 add map 的赋值用 set
a.Add(1)
a.Add(3)
g.Dump("a:", a) // 打印后果:"[3,2,1]"
// 升序数组
a2 := garray.NewSortedArray(gutil.ComparatorInt)
a2.Add(2)
a2.Add(1)
a2.Add(3)
g.Dump("a2:", a2)
// 增加反复元素
a2.Add(2)
g.Dump("a2 增加反复元素后:", a2)
a2.SetUnique(true) // 设置不容许反复元素
g.Dump("a2 设置不容许反复元素之后:", a2)
}
打印后果
join、chunk、merge
- 数据项串联是相当罕用的场景, 比方多个 id 以逗号分隔入库存储,咱们应用 join 关键字即可
- garray 反对将一个数组拆分成指定数量的二维数组,应用 chunk 关键字
- garray 反对应用 merge 关键字合并数组
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
func main() {
//join 串联 罕用于逗号宰割
a := garray.NewFrom(g.Slice{1, 2, 3, 4, 5})
fmt.Println("串联后果:", a.Join("_")) //1_2_3_4_5
// 数组拆分 chunk
fmt.Println("数组拆分:", a.Chunk(2)) //[[1 2] [3 4] [5]]
// 数组合并 能够合并数组 也能够合并 slice(原生切片和 g.Slice 都反对)a1 := garray.NewFrom(g.Slice{1, 2})
a2 := garray.NewFrom(g.Slice{3, 4})
s1 := g.Slice{5, 6}
s2 := []string{"7", "8"}
s3 := []int{9, 0}
a1.Merge(a2)
a1.Merge(s1)
a1.Merge(s2)
a1.Merge(s3)
fmt.Println("合并后果:", a1) // [1,2,3,4,5,6,7,8,9,0]
}
打印后果:
遍历
- garray 人造反对升序遍历和降序遍历
- 函数 Iterator() 是 IteratorAsc() 的别名
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
// 数组遍历 iterate
func main() {a := garray.NewFrom(g.Slice{"a", "b", "c"})
fmt.Println("升序遍历后果")
a.Iterator(func(k int, v interface{}) bool {fmt.Printf("%v,%v \n", k, v)
return true
})
// 数组倒序遍历
fmt.Println("倒序遍历后果:")
a.IteratorDesc(func(k int, v interface{}) bool {fmt.Printf("%v,%v \n", k, v)
return true
})
}
打印后果
遍历批改 walk 函数
十分好用!!!
看到这个办法,更深信了我一个观点:GF 的作者肯定写了几年 PHP。
package main
import (
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gconv"
)
//walk 遍历批改 批改数组的值
func main() {
var a garray.Array
tables := g.Slice{"user", "user_detail"}
a.Append(tables...)
prefix := "gf_"
a.Walk(func(value interface{}) interface{} {return prefix + gconv.String(value)
})
g.Dump(a)
}
打印后果
序列化和反序列化
- 这里重点提一下:gf container 容器包下的对象都实现对原生 json 包的反对,都反对序列化和反序列化。
- gf 非常重视对序列化的反对,gmap、glist、gqueue、gset、gtree… 等 gf 组件,都是反对序列化和反序列化的。
package main
import (
"encoding/json"
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
//gf container 容器包下的对象都实现对原生 json 包的反对,即都反对序列化和反序列化
func main() {
// 序列化
type student struct {
Name string
Age int
Scores *garray.IntArray
}
s := student{
Name: "王中阳",
Age: 28,
Scores: garray.NewIntArrayFrom([]int{100, 98}),
}
bytes, _ := json.Marshal(s)
g.Dump(bytes) //{"Name":"王中阳","Age":28,"Scores":[100,98]}
// 反序列化
data := []byte(`{"Name":"王中阳","Age":28,"Scores":[100,98]}`)
s2 := student{}
_ = json.Unmarshal(data, &s2)
fmt.Println(s2) //{王中阳 28 [100,98]}
}
打印后果
总结
综上咱们理解到:
- garray 反对设置并发平安开关
- 反对排序数组
- 反对数组出栈、蕴含判断、join、chunk、merge 等罕用的工具办法
- 人造反对升序遍历、遍历批改
- 人造反对序列化和反序列化
大家是不是显著感觉到 GoFrame 的 garray 比 PHP 的 array 还要好用。
更加深信 GoFrame 的作者是写过 PHP 的😄
小伙伴们还想看哪些内容,欢送在评论区留言。
本文参加了思否技术征文,欢送正在浏览的你也退出。