Golang泛型的使用

嵌入式技术

1368人已加入

描述

作者:ShadowYD

关键字参数

众所周知很多语言的function 中都支持 key=word 关键字参数, 但 golang 是不支持的, 我们可以利用泛型去简单的实现.

 

func DefaultKeyWordParams[D any](defVal D, params ...D) D {
      if len(params) == 0 {
              return defVal
      }
      return params[0]
}


func test(category ...string) {
  // 不填写则返回默认值
  realCategory := DefaultKeyWordParams[string]("AGroup", category...)
  fmt.Println(realCategory)
}

func main () {
   test()
}

 

快速排序

UpdateAt: 2023-02-22

实现一个可进行控制反转的通用类型快速排序, 解决一下原生的sort包进行类型定义的繁琐.

 

// QuickSort 通用快速排序
func QuickSort[T any](arr []T, compareFn func(a, b T) bool) {
      if len(arr) < 2 {
              return
      }

      pivot := arr[0]
      left := 1
      right := len(arr) - 1

      for left <= right {
              if compareFn(arr[left], pivot) {
                      left++
              } else if compareFn(pivot, arr[right]) {
                      right--
              } else {
                      arr[left], arr[right] = arr[right], arr[left]
              }
      }

      arr[0], arr[right] = arr[right], arr[0]

      QuickSort(arr[:right], compareFn)
      QuickSort(arr[right+1:], compareFn)
}

 

测试用例

 

func TestQuickSort(t *testing.T) {
      nums := []int{9, 3, 1, 7, 4, 8, 6, 2, 5}
      fmt.Println("Unsorted:", nums)

      QuickSort[int](nums, func(a, b int) bool {
              return a < b
      })
      fmt.Println("Sorted:  ", nums)

      strs := []string{"orange", "apple", "banana", "kiwi", "grape"}
      fmt.Println("Unsorted:", strs)

      QuickSort[string](strs, func(a, b string) bool {
              return len(a) < len(b)
      })
      fmt.Println("Sorted:  ", strs)
}


 

去重复

这是一个简单的实现, 复杂点可以通过回调 + 泛型来实现;

 

func RemoveDuplicate[T string | int | float64](duplicateSlice []T) []T {
      set := map[T]interface{}{}
      res := []T{}
      for _, item := range duplicateSlice {
              _, ok := set[item]
              if !ok {
                      res = append(res, item)
                      set[item] = nil
              }
      }
      return res
}

func main() {
      fmt.Println(RemoveDuplicate[string]([]string{"a", "c", "a"}))
      fmt.Println(RemoveDuplicate[int]([]int{1, 2, 1, 1, 1}))
}

 

通过控制反转实现通用的去重复方法, 支持任意类型;

 

type Student struct {
      Name string
      Age  int
}

func NewStudent(name string, age int) *Student {
      return &Student{Name: name, Age: age}
}

func DefaultFilter(item interface{}) (uniqueKey interface{}) {
      return item.(*Student).Name
}

func RemoveDuplicateWithFilter[T comparable](compareSlice []T, filterFunc func(item interface{}) (key interface{})) []T {
      set := map[interface{}]interface{}{}
      res := []T{}
      for _, item := range compareSlice {
              i := filterFunc(item)
              _, ok := set[i]
              if !ok {
                      res = append(res, item)
                      set[i] = nil
              }
      }
      return res
}

func main() {
      s := []*Student{
              NewStudent("a", 1),
              NewStudent("a", 1),
              NewStudent("b", 2),
              NewStudent("b", 2),
      }
      l := RemoveDuplicateWithFilter[*Student](s, DefaultFilter)
      for _, i := range l {
              fmt.Println(i.Name, i.Age)
      }
}

 

联合约束类型

该例子只是一个演示, 没有实际效果

type ID interface {
  int | string
}

// 写法  [T ID, D string] == [T int | string, D string]
type UserModel[T ID, D string] struct {
      Id   T
      Name D
}

func NewUserModel[A ID, D string](id A, name D) *UserModel[A, D] {
      return &UserModel[A, D]{Id: id, Name: name}
}

func main() {
      fmt.Println(NewUserModel[int, string](10, "hello"))
      fmt.Println(NewUserModel[string, string]("10", "hello"))
}

 

分页

这是一段线上在使用的分页代码, 当无法使用外部存储器进行分页时直接使用该对象进行分页, 支持任意类型;

type KeepItem bool

// 若需要保留的item 则返回true 即可
type FilterFunc func(item interface{}) KeepItem

type PageList[T any] struct {
      Total int `json:"total"`
      Page  int `json:"page"`
      Size  int `json:"size"`
      List  []T `json:"list"`
}

type Pager[T any] struct {
      limit   int
      offset  int
      total   int
      pageCnt int
      list    []T
}

func NewPager[T any](list []T) *Pager[T] {
      return &Pager[T]{
              limit:  10,
              offset: 1,
              total:  len(list),
              list:   list,
      }
}

func (this *Pager[T]) Filter(filterFn FilterFunc) *Pager[T] {
      tmpList := []T{}
      for _, item := range this.list {
              if filterFn(&item) {
                      tmpList = append(tmpList, item)
              }
      }
      this.list = tmpList
      this.total = len(tmpList)
      return this
}

func (this *Pager[T]) Offset(c int) *Pager[T] {
      this.offset = c
      return this
}

func (this *Pager[T]) Limit(c int) *Pager[T] {
      this.limit = c
      return this
}

func (this *Pager[T]) List() []T {
      // 页码
      if this.offset <= 0 {
              this.offset = 1
      }
      // size
      if this.limit > this.total {
              this.limit = this.total
      }
      // 总页数
      this.pageCnt = int(math.Ceil(float64(this.total) / float64(this.limit)))
      if this.offset > this.pageCnt {
              return []T{}
      }
      startIdx := (this.offset - 1) * this.limit
      endIdx := startIdx + this.limit

      if endIdx > this.total {
              endIdx = this.total
      }

      return this.list[startIdx:endIdx]
}

func (this *Pager[T]) Output() *PageList[T] {

      return &PageList[T]{
              Total: this.total,
              Page:  this.offset,
              Size:  this.limit,
              List:  this.list,
      }
}

// test
func main () {
  page := NewPager[int]([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
      list := page.Offset(1).Limit(3).Filter(func(item interface{}) KeepItem {
  if *item.(*int)%2 == 1 {
   return true
  }
  return false
      }).List()
      fmt.Println(list)
}


 

通用初始化模型

可以解决在多态下使用同一个初始化函数进行对象初始化, 写法上有点绕大家自行多实验几次就能明白.

type ModelObj interface {
      User | Product
}

type User struct {
      Uid int
}

func (this *User) SetId(id int) {
      this.Uid = id
}

type Product struct {
      Pid int
}

func (this *Product) SetId(id int) {
      this.Pid = id
}

// TrimModelObj 是一个动态类型的 Interface, 由M决定当前Interface的最终类型
type TrimModelObj[M ModelObj] interface {
      *M
      SetId(id int)
}

// TrimModelObj[Model] 由第二个参数决定当前的动态类型;
// NewModelObj[*User, User](32) 如 Model 是 User 类型, 最终 TrimModelObj == *User,所以我们需要为 Trim 传递 *User
func NewModelObj[Trim TrimModelObj[Model], Model ModelObj](id int) Trim {
      m := new(Model)
      t := Trim(m)
      fmt.Printf("%p 
", m)
      // 类型转换成指定的*Model
      t.SetId(id)
      return t
}


func main() {
      // new user model object
      user := NewModelObj[*User, User](32)
      fmt.Printf("%p 
", user)
      fmt.Printf("%T 
", user)
      fmt.Println(user.Uid)

      // new product model object
      prod := NewModelObj[*Product, Product](18)
      fmt.Printf("%p 
", prod)
      fmt.Printf("%T 
", prod)
      fmt.Println(prod.Pid)
}

 

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分