Golang对接口切片进行排序

huangapple go评论78阅读模式
英文:

Golang sorting slice of interfaces

问题

我用Golang编写了一个CLI工具,用于封装一个API,我喜欢它的简单性。现在我想将另一个具有不同JSON结构的API整合进来,以获取类似的值。我为这些结构创建了一个接口,但我不太理解Golang中的类型转换是如何工作的。

这是我编写的一个示例:

我有一个公共接口Vehicle,它公开了一些方法:

type Vehicle interface {
    Manufacturer() string
    Model() string
    Year() int
    Color() string
    String() string
}

我还想对所有实现了该接口的结构进行排序,所以我添加了一个实现了sort接口的Vehicles类型:

type Vehicles []Vehicle

func (s Vehicles) Len() int {
    return len(s)
}

func (s Vehicles) Less(i, j int) bool {
    if s[i].Manufacturer() != s[j].Manufacturer() {
        return s[i].Manufacturer() < s[j].Manufacturer()
    } else {
        if s[i].Model() != s[j].Model() {
            return s[i].Model() < s[j].Model()
        } else {
            return s[i].Year() < s[j].Year()
        }
    }
}

func (s Vehicles) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

问题是,当我用一个新的结构Car实现Vehicle接口,并尝试对一个Car结构的切片进行排序时,我得到了以下异常:

tmp/sandbox022796256/main.go:107: cannot use vehicles (type []Car) as type sort.Interface in argument to sort.Sort:
    []Car does not implement sort.Interface (missing Len method)

这是完整的代码:https://play.golang.org/p/KQb7mNXH01

更新:

@Andy Schweig提供了一个很好的解答,但我应该更明确地说明我正在将JSON解组成一组Car结构的切片,所以他的解决方案在这种更明确的情况下不适用(请参见我代码的更新链接)。

英文:

I wrote a CLI tool in Golang to wrap an API and I love how simple it was to put together. Now I want to incorporate another API with a different JSON structure to get similar values. I created an interface for the structs to implement, but I don't quite understand how the type casting works in Golang.

Here is an example I put together:

I have a common interface Vehicle that exposes some methods

type Vehicle interface {
    Manufacturer() string
    Model() string
    Year() int
    Color() string
    String() string
}

I also want to sort all structs that implement this interface so I added a Vehicles type that implements the sort interface

type Vehicles []Vehicle

func (s Vehicles) Len() int {
	return len(s)
}

func (s Vehicles) Less(i, j int) bool {
	if s[i].Manufacturer() != s[j].Manufacturer() {
		return s[i].Manufacturer() &lt; s[j].Manufacturer()
	} else {
		if s[i].Model() != s[j].Model() {
			return s[i].Model() &lt; s[j].Model()
		} else {
			return s[i].Year() &lt; s[j].Year()
		}
	}
}

func (s Vehicles) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

The issue is when I implement the Vehicle interface with a new struct Car and try to sort a slice of Cars I get this exception

tmp/sandbox022796256/main.go:107: cannot use vehicles (type []Car) as type sort.Interface in argument to sort.Sort:
    []Car does not implement sort.Interface (missing Len method)

Here is the full code: https://play.golang.org/p/KQb7mNXH01

Update:

@Andy Schweig provided a good answer to the problem I posed, but i should have been more explicit that I am unmarshalling JSON into a slice of Car structs so his solution doesn't work in this more explicit case
( Please see the updated link to my code )

答案1

得分: 1

如果你正在使用Go 1.8(或者有更新项目的选项),你可以使用新添加的sort.Slice函数来对常规切片进行排序,就像你从解析JSON中获得的切片一样。详见:https://golang.org/pkg/sort/#Slice

英文:

Extending on Andy's answer... If you're using Go 1.8 (or have the option to update for your project), you can use the newly-added sort.Slice function to do this with regular slices, like you'd get from unmarshalling JSON: https://golang.org/pkg/sort/#Slice

答案2

得分: 1

问题在于Car实现了Vehicle接口,但[]Car不是[]Vehicle。一个是对象的切片,另一个是接口的切片。
正如Andy Scheweig所说,你需要让GetVehicles返回Vehicles[]Vehicle)。你可以在GetVehicles内部进行转换,之后如果你需要Cars,可以进行类型断言。

对你的代码进行了一些修改,现在按照你的需求工作。

https://play.golang.org/p/fM8EhSfsCU

英文:

The problem is that Car implements Vehicle, but []Car is not []Vehicle. One is a slice of objects and the other is a slice of interfaces.
What you need as Andy Scheweig said, you need GetVehicles to return Vehicles ([]Vehicle). You can do the conversion inside the GetVehicles and afterwards if you need the Cars you can do type assertion.

Made some changes to your code, and works as you need it now.

https://play.golang.org/p/fM8EhSfsCU

答案3

得分: 0

你不能在期望Vehicles(或[]Vehicle)的地方使用[]Car,即使Car实现了Vehicle接口。(尽管元素类型是兼容的,切片类型是不同的类型,类型必须完全匹配。)

幸运的是,修复你的代码很容易。你只需要将GetVehicles的前几行改为以下内容:

func GetVehicles() Vehicles {
	return Vehicles{
		Car{
			CarManufacturer: "Chevrolet",
			CarModel:        "Corvette",
			CarYear:         1965,
			CarColor:        "Red",
		},

这样做是有效的,因为Car可以在期望Vehicle的地方使用,因为Car实现了Vehicle接口。

英文:

You can't use []Car where Vehicles (or []Vehicle) is expected, even though Car implements the Vehicle interface. (Even though the element types are compatible, the slice types are different types, and types must match exactly.)

Fortunately, it's easy to fix your code. You just have to change the first few lines of GetVehicles to this:

func GetVehicles() Vehicles {
	return Vehicles{
		Car{
			CarManufacturer: &quot;Chevrolet&quot;,
			CarModel:        &quot;Corvette&quot;,
			CarYear:         1965,
			CarColor:        &quot;Red&quot;,
		},

This works because Car can be used where Vehicle is expected, because Car implements the Vehicle interface.

huangapple
  • 本文由 发表于 2017年4月4日 23:04:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/43210961.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定