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 内联

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

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