Redian新闻
>
[Golang] 泛型的使用

[Golang] 泛型的使用

公众号新闻

作者:ShadowYD

https://juejin.cn/post/7194468198270861368

关键字参数

  • 众所周知很多语言的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{931748625}
          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{12111}))
    }

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

    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 stringstruct {
          Id   T
          Name D
    }

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

    func main() {
          fmt.Println(NewUserModel[intstring](10"hello"))
          fmt.Println(NewUserModel[stringstring]("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{12345678910})
          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 \n", m)
          // 类型转换成指定的*Model
          t.SetId(id)
          return t
    }


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

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

推荐阅读  点击标题可跳转

1、为什么不用Go开发操作系统?

2、解析 Golang 定时任务库 gron 设计和原理

3、初探 Golang 内联

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
体外循环后心脏复跳正性肌力药物的使用争议与选择父亲节,纪念父亲Sandro秋促3折!Longchamp狂甩4折!赫莲娜套装7折!MANGO半价!弃 Ubuntu 转 Manjaro 一周后的使用体验 | Linux 中国川普:我走入虎穴, 永不放弃拯救美国的使命【𝐂𝐚𝐥𝐧𝐢𝐊𝐞𝐚𝐧双皮奶无痕内裤】49元三条!巨巨巨好穿 !!简直就是辣妹顶配,食品级冰箱收纳盒【一日团】To Stop Teen From Moving, Chongqing Mom Flees With School Papers剪辑师的使命是什么?Nat Biotechnol | 胡政/周达合作建立基于演化时钟模型的单细胞轨迹推断技术用Colingo,开发AI应用就像做可颂一样简单香港建筑分包商:Ming Shing Group Holdings 向美SEC公开递交纳斯达克上市招股书大话三国278:张飞的使用技巧,马超和张飞到底谁厉害?nǚ hóng?nǚ gōng这种乱逻辑也能宇宙普适?NeurIPS 2023 | 超越YOLO系列!华为提出Gold-YOLO:实时目标检测新SOTA行乐要及时呀每天10句英语口语|Everything's going to be OKSchool Gym Collapse Kills 11, Girl Volleyball Players Among Dead剪辑师的使命——挖掘素材的最大潜力Erklärung zur Zusammenarbeit詹纳,疫苗的使者 | 新书首发您的梦想,我们的使命!贝特曼发布高级法律套餐,守护“资金、绿卡”双安全观点|宋伟:BRICS play bigger role in improving global governanceAmEx Platinum 80k & AmEx Gold 60k可Churn链接 (No Lifetime Language)Walking Around a City Is China’s Golden Week Travel Trend一文看懂 Pingora 比 Nginx 强在哪图文详解 Java 泛型,写得太好了!国庆黄金周的"黄金",英文是 gold 还是 golden?战地恋情(九)𝐂𝐚𝐥𝐧𝐢𝐊𝐞𝐚𝐧双皮奶内衣裤,软弹有度,上身0束缚~那是你的使命,不是我的两首合唱:《天边飘过故乡的云》&《秋蝉》全球美元体系以及它的使用方法"为持有人创造价值,是基金公司的使命与良知!"平安基金罗春风:要坚持做长期正确的事情,事上磨,心上练!儿童急性中耳炎抗生素的使用时机,看这一篇就够了!
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。