英文:
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])) < 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] < 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{"one", "two", "three", "four"}
sort.Strings(*(*[]string)(unsafe.Pointer(&objects)))
答案2
得分: 1
如果你的MyObject
类型是一个别名,其底层类型为string
,那么你无法直接进行转换。可以参考@JimB的答案。
MyObject
的底层类型与string
的底层类型相同(都是string
),但[]MyObject
的底层类型与[]string
的底层类型不同。
可以在以下链接中找到更详细的解释:
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/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{"abc", "aaa"}
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{"abc", "aaa"}
objects.Sort()
fmt.Println(objects)
(Output is the same.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论