• 【开源库推荐】go-linq 强大的语言集成查询库如,ORM一般丝滑处理内存数据


    在这里插入图片描述
    在业务开发过程中除了业务逻辑、数据库之外主要就是数据转换处理过滤等相关的内容,比如合法性验证(可以使用”go-playground/validator“)但是golang在数据处理上面尤其是对结构体上官方几乎没有提供一些便捷的方式,大部分都只能使用for、if等方式自己来处理,也有研发用偷懒的方式全部交给数据库写出了N张表的关联导致了数据库瓶颈等问题。

    那么有没有什么更加方便好用的方法来更加方便的处理数据又能够降低代码复杂度,写出更加可读的代码呢?答案是肯定了,比如go-zero中的fx流处理比较适合离线数据统计处理和mr比较适合实时数据并发处理,但今天给大家介绍的主角是“go-linq”通过类ORM的链式方式来进行数据处理。

    资料:

    golint特性:

    • 用 vanilla Go 编写,没有依赖关系!
    • 使用迭代器模式完成惰性求值
    • 支持并发安全
    • 支持泛型函数,使您的代码更简洁且没有类型断言(但降低性能)
    • 支持数组、切片、映射、字符串、通道和自定义集合

    一、🌰开头

    首先我们来看一个例子,一个简单的struct获取age大于等于18的ID变成一个slice来给到后面的SQL执行in查询,按照一般的做法就直接开始for循环+if判断+赋值了。

    type Person struct {
    	ID   int64
    	Age  int64
    	Name string
    }
    
    func getPersonIDList(persons []*Person) []int64 {
    	personIDList := make([]int64, 0, len(persons))
    	for _, person := range persons {
    		if person.Age >= 18 {
    			personIDList = append(personIDList, person.ID)
    		}
    	}
    	return personIDList
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果是java程序是怎么做的呢? 基于java8的特性可以很方便的通过stream -> filter -> map -> collect来获取出想要的内容也非常简洁

    public class Test (
      @Data
      public static class Person (
        private Long id;
        private Integer age;
        private String name;
      }
      
      public List<Long> getPersonIdList(List<Person> personList) {
        return personList.stream()
                         .filter(person -> person.age >= 18)
                         .map(Person::getId).collect(Collectors. toList());
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    导入依赖包

    go get github.com/ahmetb/go-linq/v3
    
    • 1

    如果使用了go-linq也就可以实现类似的效果了,看起来清爽很多

    type Person struct {
    	ID   int64
    	Age  int64
    	Name string
    }
    
    func getPersonIDList(persons []*Person) (personIDList []int64) {
    	linq.From(persons).
    		WhereT(func(person *Person) bool { return person.Age >= 18 }).
    		SelectT(func(person *Person) int64 { return person.ID }).ToSlice(&personIDList)
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    PS:如果你在意性能并且list比较大就不推荐使用WhereT、SelectT,应该使用Where、Select通过interface来接受入参进行断言避免反射带来的开销,纯性能差距大改造 5 到 10 倍

    二、go-linq的功能及场景

    官方例子:查找出书最多的作者

    	type Book struct {
    		id      int
    		title   string
    		authors []string
    	}
    	var books []Book
    	author := From(books).
    		SelectMany( // make a flat array of authors
    			func(book interface{}) Query {
    				return From(book.(Book).authors)
    			}).
    		GroupBy( // group by author
    			func(author interface{}) interface{} {
    				return author // author as key
    			}, func(author interface{}) interface{} {
    				return author // author as value
    			}).
    		OrderByDescending( // sort groups by its length
    			func(group interface{}) interface{} {
    				return len(group.(Group).Group)
    			}).
    		Select( // get authors out of groups
    			func(group interface{}) interface{} {
    				return group.(Group).Key
    			}).
    		First() // take the first author
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    ForEach

    	fruits := []string{"orange", "apple", "lemon", "apple"}
    	linq.From(fruits).ForEachIndexedT(func(i int, fruit string) {
    		fmt.Println(i, fruit)
    	})
    
    • 1
    • 2
    • 3
    • 4

    Where

    	fruits := []string{"apple",
    		"passionfruit",
    		"banana",
    		"mango",
    		"orange",
    		"blueberry",
    		"grape",
    		"strawberry"}
    
    	var query []string
    	linq.From(fruits).WhereT(func(f string) bool { return len(f) > 6 }).ToSlice(&query)
    	fmt.Println(query)
    
    	numbers := []int{0, 30, 20, 15, 90, 85, 40, 75}
    	var query2 []int
    	linq.From(numbers).WhereIndexedT(func(index int, number int) bool { return number <= index*10 }).ToSlice(&query2)
    	fmt.Println(query2)
    }
    
    type Product struct {
    	Name string
    	Code int
    }
    
    func Test_Distinct(t *testing.T) {
    	ages := []int{21, 46, 46, 55, 17, 22, 55, 55}
    	var distinctAges []int
    	linq.From(ages).
    		OrderBy(
    			func(item interface{}) interface{} { return item },
    		).
    		Distinct().
    		ToSlice(&distinctAges)
    	fmt.Println(distinctAges)
    
    	products := []Product{
    		{Name: "apple", Code: 9},
    		{Name: "orange", Code: 4},
    		{Name: "apple", Code: 9},
    		{Name: "Lemon", Code: 12},
    	}
    
    	var noduplicates []Product
    	linq.From(products).
    		DistinctByT(
    			func(item Product) int { return item.Code },
    		).
    		ToSlice(&noduplicates)
    	for _, product := range noduplicates {
    		fmt.Printf("%s %d\n", product.Name, product.Code)
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    Except

    	fruits1 := []Product{
    		{Name: "apple", Code: 9},
    		{Name: "orange", Code: 4},
    		{Name: "apple", Code: 9},
    		{Name: "Lemon", Code: 12},
    	}
    
    	fruits2 := []Product{{Name: "apple", Code: 9}}
    
    	//Order and exclude duplicates.
    	var except []Product
    	linq.From(fruits1).
    		ExceptByT(linq.From(fruits2),
    			func(item Product) int { return item.Code },
    		).
    		ToSlice(&except)
    
    	for _, product := range except {
    		fmt.Printf("%s %d\n", product.Name, product.Code)
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Intersect

    	storel := []Product{
    		{Name: "orange", Code: 4},
    		{Name: "apple", Code: 9},
    	}
    	store2 := []Product{
    		{Name: "lemon", Code: 12},
    		{Name: "apple", Code: 9},
    	}
    
    	var duplicates []Product
    	linq.From(storel).
    		IntersectByT(linq.From(store2),
    			func(p Product) int { return p.Code },
    		).
    		ToSlice(&duplicates)
    
    	for _, p := range duplicates {
    		fmt.Println(p.Name, p.Code)
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    更多的例子可以参考官方的单测实现:

    • https://github.com/ahmetb/go-linq/blob/master/groupjoin_test.go
    • https://github.com/ahmetb/go-linq/blob/master/aggregate_test.go
  • 相关阅读:
    (十) 共享模型之内存【有序性】
    关于Flask高级_上下文的介绍和基本操作
    运维去大公司好还是小公司好?你怎么看?
    MySQL连接方式: Unix套接字 & TCP/IP
    02设计模式——单例模式
    国庆day2---select实现服务器并发
    Leetcode算法训练日记 | day35
    实例讲解Simulink的MATLAB Function模块
    【K哥爬虫普法】网盘用的好,“艳照门”跑不了
    Console 线连接路由器交换机等设备
  • 原文地址:https://blog.csdn.net/u011142688/article/details/126916101