如何对元素类型为字符串别名(而不是字符串本身)的 Go 切片进行排序?

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

How can I sort Go slices whose element type is an alias of string, but not string itself?

问题

你想对这些对象进行排序。标准库中有sort.Strings,但它要求使用[]string的实例而不是[]MyObject

你目前的解决方案是实现sort.Interface(如下所示),然后使用sort.Sort,但我想摆脱那些样板代码。有没有更好的方法?

type MyObjects []MyObject

func (objs MyObjects) Len() int {
    return len(objs)
}

func (objs MyObjects) Less(i, j int) bool {
    return strings.Compare(string(objs[i]), string(objs[j])) < 0
}

func (objs MyObjects) Swap(i, j int) {
    o := objs[i]
    objs[i] = objs[j]
    objs[j] = o
}
英文:
type MyObject string
var objects []MyObject

I want to sort these objects. The standard library has sort.Strings, but that requires an instance of []string instead of []MyObject.

My current solution is to implement sort.Interface (as shown below) and use sort.Sort, but I'd like to get rid of that boilerplate code. Is there a nicer way?

type MyObjects []MyObject

func (objs MyObjects) Len() int {
	return len(objs)
}

func (objs MyObjects) Less(i, j int) bool {
	return strings.Compare(string(objs[i]), string(objs[j])) &lt; 0
}

func (objs MyObjects) Swap(i, j int) {
	o := objs[i]
	objs[i] = objs[j]
	objs[j] = o
}

答案1

得分: 6

不。由于Go语言不允许在切片中进行隐式类型转换(接口也不支持协变),你需要为你的类型提供相应的方法。

type MyObjects []MyObject

func (p MyObjects) Len() int           { return len(p) }
func (p MyObjects) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p MyObjects) Less(i, j int) bool { return p[i] < p[j] }

如果你真的想这样做,你可以使用unsafe包(但请不要这样做)。我怀疑这额外的3行安全代码对你来说不会有太大的影响。

objects := []MyObject{"one", "two", "three", "four"}
sort.Strings(*(*[]string)(unsafe.Pointer(&objects)))

链接:http://play.golang.org/p/d6ciFjjr2c

英文:

No. Since Go doesn't allow the implicit conversion of types within slices (there is also no covariance with interfaces), you need to supply the appropriate methods for your type.

type MyObjects []MyObject

func (p MyObjects) Len() int           { return len(p) }
func (p MyObjects) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p MyObjects) Less(i, j int) bool { return p[i] &lt; p[j] }

If you really want to do this, you could use unsafe (but please don't). I doubt those 3 extra lines of safe code are going to make that big a difference for you.

http://play.golang.org/p/d6ciFjjr2c

objects := []MyObject{&quot;one&quot;, &quot;two&quot;, &quot;three&quot;, &quot;four&quot;}
sort.Strings(*(*[]string)(unsafe.Pointer(&amp;objects)))

答案2

得分: 1

如果你的MyObject类型是一个别名,其底层类型为string,那么你无法直接进行转换。可以参考@JimB的答案

MyObject的底层类型与string的底层类型相同(都是string),但[]MyObject的底层类型与[]string的底层类型不同。

可以在以下链接中找到更详细的解释:

https://stackoverflow.com/questions/29031353/conversion-of-a-slice-of-string-into-a-slice-of-custom-type

https://stackoverflow.com/questions/31891493/why-are-you-unable-convert-slice-types

但是,如果你稍微重构一下你的类型系统,问题就会解决:

type MyObjects []string

var objects MyObjects

func main() {
	objects = MyObjects{"abc", "aaa"}
	sort.Strings(objects)
	fmt.Println(objects)
}

输出结果(在Go Playground上尝试):

[aaa abc]

为了方便起见,你甚至可以为其提供一个Sort()方法:

func (m MyObjects) Sort() {
	sort.Strings(m)
}

然后使用它:

objects = MyObjects{"abc", "aaa"}
objects.Sort()
fmt.Println(objects)

(输出结果相同。)

英文:

IF your MyObject type is an "alias" with string being its underlying type, you can't. See @JimB's answer here.

The underlying type of MyObject is the same as the underlying type of string (which is itself: string), but the underlying type of []MyObject is not the same as the underlying type of []string.

See further explanations here:

https://stackoverflow.com/questions/29031353/conversion-of-a-slice-of-string-into-a-slice-of-custom-type

https://stackoverflow.com/questions/31891493/why-are-you-unable-convert-slice-types

But if you happen to refactor a little your type system, your problems go away:

type MyObjects []string

var objects MyObjects

func main() {
	objects = MyObjects{&quot;abc&quot;, &quot;aaa&quot;}
	sort.Strings(objects)
	fmt.Println(objects)
}

Output (try it on the <kbd>Go Playground</kbd>):

[aaa abc]

For convenience, you can even provide a Sort() method on it if you want to:

func (m MyObjects) Sort() {
	sort.Strings(m)
}

And using it:

objects = MyObjects{&quot;abc&quot;, &quot;aaa&quot;}
objects.Sort()
fmt.Println(objects)

(Output is the same.)

huangapple
  • 本文由 发表于 2015年8月25日 02:44:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/32189487.html
匿名

发表评论

匿名网友

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

确定