为什么我觉得GoFrame的garray比PHP的array还好用?

点击下方卡片,在公众号后台回复:Go,就可以获得免费硬核的《Go语言学习专栏》,优质内容持续更新中。

前言

写过PHP的同学都知道 PHP的数组Array非常好用,特别灵活

我在写PHP之前使用Java做安卓开发,在接触PHP的数组Array之后,直呼太香了!

而在学习Go基础知识的时候了解到:Go的数组和PHP的数组并不一样;从一定程度上讲,Go的slice切片类型和PHP的数组array更像(不固定长度、引用类型、动态扩容等),但是在开发使用中Go的切片和数组远远不如PHP的数组array灵活。

初识GoFrame

最近在使用基于Go语言的GoFrame框架开发项目,发现GoFrame封装的garray竟然比PHP的array还要好用。

近期已经更新了一系列GoFrame的文章,下文将GoFrame简称为gf。感兴趣的同学可以关注我的专栏:Go语言学习专栏。

gf框架有个特点,提供的组件基本都支持设置并发安全开关。显然PHP是不支持并发安全开关的,PHP的数组是并发安全的。PHP-FPM是阻塞的单线程模型,PHP-FPM每个进程里只有一个线程,一个进程同时只能服务一个客户端。

garray特点简介

  1. garray支持int/string/interface{}三种常用的数据类型。

  2. garray支持普通数组和排序数组,普通数组的结构体名称定义为Array格式,排序数组的结构体名称定义为SortedArray格式,如下:Array, intArray, StrArray,SortedArray, SortedIntArray, SortedStrArray

  3. 其中排序数组SortedArray,需要给定排序比较方法,在工具包gutil中也定义了很多ComparatorXXX的比较方法,用起来很方便。当然也支持自定义排序方式。

注意:为了行文紧凑,下面的代码段都省略了import的包依赖,小伙伴们参考这篇文章敲代码时,编辑器能自动补全缺少的import。

基本使用

package mainfunc 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())
}

打印结果

c562a02a28648eb08960d2aa6473f24f.png

数组出栈

  1. 数组出栈使用Pop*关键字

  2. 数组可以按顺序出栈,而gf提供的另外一个数据类型gmap的pop*方法是随机出栈 (关注我,会在后续的文章中更新说明)

  3. garray随机出栈,我们可以使用rand()或者popRand()

package main//数组出栈 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)

}

包含判断

  1. 注意:Contains()是区分大小写

  2. 空值过滤使用:FilterEmpty

  3. nil过滤使用:FilterNil

package main//包含 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())
}

打印结果

d95e9b9782e01ca96c255430603e9dfc.png

排序数组

  1. 我们可以自定义NewSortedArray的排序规则,以实现是升序数组还是降序数组;

  2. 排序数组还有唯一性校验的功能:garray.SetUnique(true)

  3. gf框架的gutil工具包定义好了常用的排序规则

package main//我们可以自定义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)
}

打印结果

8c715a192d708f22cfcccb204434eb5a.png

join、chunk、merge

  1. 数据项串联是相当常用的场景,比如多个id以逗号分隔入库存储,我们使用join关键字即可

  2. garray支持将一个数组拆分成指定数量的二维数组,使用chunk关键字

  3. garray支持使用merge关键字合并数组

package mainfunc 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]}

打印结果:

fd5c3ff88b46d47b9c54987e1fbccd7e.png

遍历

  1. garray天然支持升序遍历和降序遍历

  2. 函数Iterator()是IteratorAsc()的别名

package main//数组遍历 iteratefunc 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
   })
}

打印结果

c4265c6178afd80bf949b805703463b6.png

遍历修改 walk函数

非常好用!!!

看到这个方法,更坚信了我一个观点:GF的作者一定写了几年PHP。

package main//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)
}

打印结果

56999d1c4afb23cd0c7b97d11c6d1a31.png

序列化和反序列化

  1. 这里重点提一下:gf container容器包下的对象都实现对原生json包的支持,都支持序列化和反序列化。

  2. gf非常重视对序列化的支持,Go语言学习专栏 文章中介绍了gmap、glist、gqueue、gset、gtree...等gf组件,都是支持序列化和反序列化的。

package main//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]}}

打印结果

6b0d775bd7316882b63345e29cde93b3.png

总结

综上我们了解到:

  1. garray支持设置并发安全开关

  2. 支持排序数组

  3. 支持数组出栈、包含判断、join、chunk、merge等常用的工具方法

  4. 天然支持升序遍历、遍历修改

  5. 天然支持序列化和反序列化

大家是不是明显感觉到GoFrame的garray比PHP的array还要好用。

更加坚信GoFrame的作者是写过PHP的😄

推荐阅读:

我为什么能被掘金签约,却没能坚持写公众号呢?

程序员的平均工资是什么水平?

为什么Java和PHP越来越“卷”?为什么Go语言值得学习?

08ac45eb972cc681f2cfbcd6a846f495.gif

一起变强!一起升级打怪! 😉

长按/扫描添加我!

回复 [加群],进群与大佬们一起共同进步!

回复 [专栏],获取GO/JAVA/PHP专栏链接!

朋友圈不定期举行送书活动。一起加油!

536cdcf9a0a6b630e398331a17b8a8c8.jpeg

7341a5b43b75fbe4920c2c356595784c.gif

62704c72df088dd9ec0d55c3748ba51d.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王中阳Go

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值