Golang泛型的使用

2023-08-16 12:10:01 来源:稀土掘金技术社区

作者:ShadowYD


(资料图)

关键字参数

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

funcDefaultKeyWordParams[Dany](defValD,params...D)D{iflen(params)==0{returndefVal}returnparams[0]}functest(category...string){//不填写则返回默认值realCategory:=DefaultKeyWordParams[string]("AGroup",category...)fmt.Println(realCategory)}funcmain(){test()}

快速排序

UpdateAt: 2023-02-22

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

//QuickSort通用快速排序funcQuickSort[Tany](arr[]T,compareFnfunc(a,bT)bool){iflen(arr)<2{return}pivot:=arr[0]left:=1right:=len(arr)-1forleft<=right{ifcompareFn(arr[left],pivot){left++}elseifcompareFn(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)}

测试用例

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

去重复

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

funcRemoveDuplicate[Tstring|int|float64](duplicateSlice[]T)[]T{set:=map[T]interface{}{}res:=[]T{}for_,item:=rangeduplicateSlice{_,ok:=set[item]if!ok{res=append(res,item)set[item]=nil}}returnres}funcmain(){fmt.Println(RemoveDuplicate[string]([]string{"a","c","a"}))fmt.Println(RemoveDuplicate[int]([]int{1,2,1,1,1}))}

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

typeStudentstruct{NamestringAgeint}funcNewStudent(namestring,ageint)*Student{return&Student{Name:name,Age:age}}funcDefaultFilter(iteminterface{})(uniqueKeyinterface{}){returnitem.(*Student).Name}funcRemoveDuplicateWithFilter[Tcomparable](compareSlice[]T,filterFuncfunc(iteminterface{})(keyinterface{}))[]T{set:=map[interface{}]interface{}{}res:=[]T{}for_,item:=rangecompareSlice{i:=filterFunc(item)_,ok:=set[i]if!ok{res=append(res,item)set[i]=nil}}returnres}funcmain(){s:=[]*Student{NewStudent("a",1),NewStudent("a",1),NewStudent("b",2),NewStudent("b",2),}l:=RemoveDuplicateWithFilter[*Student](s,DefaultFilter)for_,i:=rangel{fmt.Println(i.Name,i.Age)}}

联合约束类型

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

typeIDinterface{int|string}//写法[TID,Dstring]==[Tint|string,Dstring]typeUserModel[TID,Dstring]struct{IdTNameD}funcNewUserModel[AID,Dstring](idA,nameD)*UserModel[A,D]{return&UserModel[A,D]{Id:id,Name:name}}funcmain(){fmt.Println(NewUserModel[int,string](10,"hello"))fmt.Println(NewUserModel[string,string]("10","hello"))}

分页

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

typeKeepItembool//若需要保留的item则返回true即可typeFilterFuncfunc(iteminterface{})KeepItemtypePageList[Tany]struct{Totalint`json:"total"`Pageint`json:"page"`Sizeint`json:"size"`List[]T`json:"list"`}typePager[Tany]struct{limitintoffsetinttotalintpageCntintlist[]T}funcNewPager[Tany](list[]T)*Pager[T]{return&Pager[T]{limit:10,offset:1,total:len(list),list:list,}}func(this*Pager[T])Filter(filterFnFilterFunc)*Pager[T]{tmpList:=[]T{}for_,item:=rangethis.list{iffilterFn(&item){tmpList=append(tmpList,item)}}this.list=tmpListthis.total=len(tmpList)returnthis}func(this*Pager[T])Offset(cint)*Pager[T]{this.offset=creturnthis}func(this*Pager[T])Limit(cint)*Pager[T]{this.limit=creturnthis}func(this*Pager[T])List()[]T{//页码ifthis.offset<=0{this.offset=1}//sizeifthis.limit>this.total{this.limit=this.total}//总页数this.pageCnt=int(math.Ceil(float64(this.total)/float64(this.limit)))ifthis.offset>this.pageCnt{return[]T{}}startIdx:=(this.offset-1)*this.limitendIdx:=startIdx+this.limitifendIdx>this.total{endIdx=this.total}returnthis.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,}}//testfuncmain(){page:=NewPager[int]([]int{1,2,3,4,5,6,7,8,9,10})list:=page.Offset(1).Limit(3).Filter(func(iteminterface{})KeepItem{if*item.(*int)%2==1{returntrue}returnfalse}).List()fmt.Println(list)}

通用初始化模型

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

typeModelObjinterface{User|Product}typeUserstruct{Uidint}func(this*User)SetId(idint){this.Uid=id}typeProductstruct{Pidint}func(this*Product)SetId(idint){this.Pid=id}//TrimModelObj是一个动态类型的Interface,由M决定当前Interface的最终类型typeTrimModelObj[MModelObj]interface{*MSetId(idint)}//TrimModelObj[Model]由第二个参数决定当前的动态类型;//NewModelObj[*User,User](32)如Model是User类型,最终TrimModelObj==*User,所以我们需要为Trim传递*UserfuncNewModelObj[TrimTrimModelObj[Model],ModelModelObj](idint)Trim{m:=new(Model)t:=Trim(m)fmt.Printf("%p",m)//类型转换成指定的*Modelt.SetId(id)returnt}funcmain(){//newusermodelobjectuser:=NewModelObj[*User,User](32)fmt.Printf("%p",user)fmt.Printf("%T",user)fmt.Println(user.Uid)//newproductmodelobjectprod:=NewModelObj[*Product,Product](18)fmt.Printf("%p",prod)fmt.Printf("%T",prod)fmt.Println(prod.Pid)}
审核编辑:汤梓红

标签:

上一篇:如何选择算运算放大器?(运算放大器原理图)
下一篇:最后一页