关于go:PHP转GO必看为什么我觉得GoFrame的garray比PHP的array还好用

34次阅读

共计 5618 个字符,预计需要花费 15 分钟才能阅读完成。

前言

写过 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 特点简介

  1. garray 反对 int/string/interface{} 三种罕用的数据类型。
  2. garray 反对一般数组和排序数组,一般数组的构造体名称定义为 Array 格局,排序数组的构造体名称定义为 SortedArray 格局,如下:Array, intArray, StrArray,SortedArray, SortedIntArray, SortedStrArray
  3. 其中排序数组 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())
}

打印后果

数组出栈

  1. 数组出栈应用 Pop* 关键字
  2. 数组能够按程序出栈,而 gf 提供的另外一个数据类型 gmap 的 pop* 办法是随机出栈 (关注我,会在后续的文章中更新阐明)
  3. 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)

}

蕴含判断

  1. 留神:Contains() 是辨别大小写
  2. 空值过滤应用:FilterEmpty
  3. 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())
}

打印后果

排序数组

  1. 咱们能够自定义 NewSortedArray 的排序规定,以实现是升序数组还是降序数组;
  2. 排序数组还有唯一性校验的性能:garray.SetUnique(true)
  3. 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

  1. 数据项串联是相当罕用的场景, 比方多个 id 以逗号分隔入库存储,咱们应用 join 关键字即可
  2. garray 反对将一个数组拆分成指定数量的二维数组,应用 chunk 关键字
  3. 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]
}

打印后果:

遍历

  1. garray 人造反对升序遍历和降序遍历
  2. 函数 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)
}

打印后果

序列化和反序列化

  1. 这里重点提一下:gf container 容器包下的对象都实现对原生 json 包的反对,都反对序列化和反序列化。
  2. 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]}
}

打印后果

总结

综上咱们理解到:

  1. garray 反对设置并发平安开关
  2. 反对排序数组
  3. 反对数组出栈、蕴含判断、join、chunk、merge 等罕用的工具办法
  4. 人造反对升序遍历、遍历批改
  5. 人造反对序列化和反序列化

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

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

小伙伴们还想看哪些内容,欢送在评论区留言。

本文参加了思否技术征文,欢送正在浏览的你也退出。

正文完
 0