go-linq按照时间排序

写惯了C#的linq,对集合进行各种操作,很丝滑,突然写go的时候,操作slice不知所措。
于是在github上找到了这个库:https://github.com/ahmetb/go-linq,又回到了丝滑的感觉。
但是在按照时间排序的时候,报错了。
先上代码:

package main

import (
	"fmt"
	"time"

	"github.com/ahmetb/go-linq/v3"
)

func main() {
	list := make([]Person, 0)
	list = append(list,
		Person{
			Name: "tony1",
			Age:  1,
			Born: time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local),
		}, Person{
			Name: "tony2",
			Age:  1,
			Born: time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local),
		},
		Person{
			Name: "tony3",
			Age:  1,
			Born: time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local),
		})
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface{}) interface{} { return i.(Person).Born }).ToSlice(&orderedList)
	fmt.Println(orderedList)
}

type Person struct {
	Name string
	Age  int
	Born time.Time
}

运行报如下错误:
panic: interface conversion: time.Time is not linq.Comparable: missing method CompareTo
在这里插入图片描述
说的是time.Time不是linq.Comparable。
查看linq.Comparable,发现定义如下:

// Comparable is an interface that has to be implemented by a custom collection
// elements in order to work with linq.
//
// Example:
// 	func (f foo) CompareTo(c Comparable) int {
// 		a, b := f.f1, c.(foo).f1
//
// 		if a < b {
// 			return -1
// 		} else if a > b {
// 			return 1
// 		}
//
// 		return 0
// 	}
type Comparable interface {
	CompareTo(Comparable) int
}

连同注释一起复制过来了,意思是要实现比较,就必须让类型实现Comparable 接口。
那么如何让time.Time实现linq.Comparable接口呢?

错误的尝试:
这还不简单,直接写一个time.Time的对象方法,这样time.Time不就自动实现了linq.Comparable接口了

func (a time.Time) CompareTo(c linq.Comparable) int {
	b := c.(time.Time)
	if a.After(b) {
		return 1
	} else if a.Equal(b) {
		return 0
	} else {
		return -1
	}
}

But,当写完这个方法之后,发现报错了!!!
在这里插入图片描述
意思是,time.Time没有在main包中定义,原来go只允许拓展struct所在包的方法

正确的方式

既然time.Time没有定义在main包,那我们自己定义一种类型,在自己的类型上实现linq.Comparable这个方法,而我们自定义的类型,与time.Time肯定有着千丝万缕的关系。

C#的面向对象思想:组合优于继承
那就用组合的方式,将time.Time包装到自定义类型的里面,更改后的代码如下:

方式一
package main

import (
	"fmt"
	"time"

	"github.com/ahmetb/go-linq/v3"
)

func main() {
	list := make([]Person, 0)
	list = append(list,
		Person{
			Name: "tony1",
			Age:  1,
			Born: time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local),
		}, Person{
			Name: "tony2",
			Age:  1,
			Born: time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local),
		},
		Person{
			Name: "tony3",
			Age:  1,
			Born: time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local),
		})
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface{}) interface{} { return NewMytime(i.(Person).Born) }).ToSlice(&orderedList)
	fmt.Println(orderedList)
}

type Person struct {
	Name string
	Age  int
	Born time.Time
}

type Mytime struct {
	Time time.Time
}

func NewMytime(t time.Time) Mytime {
	return Mytime{Time: t}
}
func (a Mytime) CompareTo(c linq.Comparable) int {
	b := c.(Mytime)
	if a.Time.After(b.Time) {
		return 1
	} else if a.Time.Equal(b.Time) {
		return 0
	} else {
		return -1
	}
}
方式二
package main

import (
	"fmt"
	"time"

	"github.com/ahmetb/go-linq/v3"
)

func main() {
	list := make([]Person, 0)
	list = append(list,
		Person{
			Name: "tony1",
			Age:  1,
			Born: NewMytime(time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local)),
		}, Person{
			Name: "tony2",
			Age:  1,
			Born: NewMytime(time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local)),
		},
		Person{
			Name: "tony3",
			Age:  1,
			Born: NewMytime(time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local)),
		})
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface{}) interface{} { return i.(Person).Born }).ToSlice(&orderedList)
	fmt.Println(orderedList)
}

type Person struct {
	Name string
	Age  int
	Born Mytime
}

type Mytime struct {
	Time time.Time
}

func NewMytime(t time.Time) Mytime {
	return Mytime{Time: t}
}
func (a Mytime) CompareTo(c linq.Comparable) int {
	b := c.(Mytime)
	if a.Time.After(b.Time) {
		return 1
	} else if a.Time.Equal(b.Time) {
		return 0
	} else {
		return -1
	}
}

最后运行,结果跟预期的一致:
在这里插入图片描述

以上两种方式,都是定义一个Mytimetime.Time聚合在里面。
但是反问自己,真的不能用继承的方式吗???
于是有了第三种方式的解法:

方式三

先定义一个time.Time的类型叫CustomTime,并实现linq.Comparable接口

type CustomTime time.Time

func (a CustomTime) CompareTo(c linq.Comparable) int {
	aa := time.Time(a)
	bb := time.Time(c.(CustomTime))
	if aa.After(bb) {
		return 1
	} else if aa.Equal(bb) {
		return 0
	} else {
		return -1
	}
}

排序的时候,强制转换为CustomTime类型:

func main() {
	list := make([]Person, 0)
	list = append(list,
		Person{
			Name: "tony1",
			Age:  1,
			Born: time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local),
		}, Person{
			Name: "tony2",
			Age:  1,
			Born: time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local),
		},
		Person{
			Name: "tony3",
			Age:  1,
			Born: time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local),
		})
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface{}) interface{} { return CustomTime(i.(Person).Born) }).ToSlice(&orderedList)
	fmt.Println(orderedList)
}

return CustomTime(i.(Person).Born)这里就是将time.Time强制转换为CustomTime因为它们是同一个类型
以后遇到要拓展第三方包或者系统struct的类型时,就推荐使用第三种方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值