我无法找到一种干净的方法来实现适用于任何类型的算法.
以下代码会在尝试将字符串或类型化切片转换为接口时产生错误,并且您无法比较接口{}对象: invalid operation: result[0] > result[n - 1] (operator > not defined on interface)
func main() {
c := Algo("abc")
//...
c := Algo([3]int{1,2,3})
//...
}
func Algo(list []interface{}) chan []interface{} {
n := len(list)
out := make(chan []interface{})
go func () {
for i := 0; i < n; i++ {
result := make([]interface{}, n)
copy(result, list)
// an actually useful algorithm goes here:
if (result[0] > result[n-1]) {
result[0], result[n-1] = result[n-1], result[0]
}
out <- result
}
close(out)
}()
return out
}
Run Code Online (Sandbox Code Playgroud)
虽然这很痛苦(我认为它应该是自动的),但我可以手动将打包和取消打包的切片放入接口{},上面真正的问题是比较.它只是越来越多的kludgy.
a := [3]int{1,2,3}
b := make([]interface{}, len(a))
for i, _ := range a {
b[i] = a[i]
}
Run Code Online (Sandbox Code Playgroud)
我甚至想过使用vector.Vector,但很多人都说不要使用它们.
那么我应该为int切片和字符串实现相同的算法吗?myObject的片段怎么样?我可以使用自定义比较函数创建一个界面,但是如何使它与标准类型一起使用?
Son*_*nia 11
您可以在Go中使用接口执行此操作.采用接口类型的函数是通用的,因为它不关心底层具体类型的数据表示.它通过方法调用完成所有操作.
要制作算法的通用版本,您必须确定算法对数据对象所需的所有功能,并且必须定义抽象这些功能的方法.抽象方法签名成为接口的方法集.
要使类型与此类通用算法兼容,请在类型上定义方法以满足算法参数的接口.
我将采用您的示例代码并显示一种方法来执行此操作.大多数所需的功能恰好由sort.Interface覆盖,所以我选择嵌入它.只需要一个其他功能,一个用于复制数据.
type algoContainer interface {
sort.Interface
Copy() algoContainer
}
Run Code Online (Sandbox Code Playgroud)
下面是一个完整的工作程序,由您的示例代码构成.
package main
import (
"fmt"
"sort"
)
func main() {
s1 := sortableString("abc")
c1 := Algo(s1)
fmt.Println(s1, <-c1)
s2 := sortable3Ints([3]int{1,2,3})
c2 := Algo(&s2)
fmt.Println(s2, <-c2)
}
type algoContainer interface {
sort.Interface
Copy() algoContainer
}
type sortableString []byte
func (s sortableString) Len() int { return len(s) }
func (s sortableString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s sortableString) Less(i, j int) bool { return s[i] < s[j] }
func (s sortableString) Copy() algoContainer {
return append(sortableString{}, s...)
}
func (s sortableString) String() string { return string(s) }
type sortable3Ints [3]int
func (sortable3Ints) Len() int { return 3 }
func (s *sortable3Ints) Swap(i, j int) {
(*s)[i], (*s)[j] = (*s)[j], (*s)[i]
}
func (s sortable3Ints) Less(i, j int) bool { return s[i] < s[j] }
func (s sortable3Ints) Copy() algoContainer { c := s; return &c }
func Algo(list algoContainer) chan algoContainer {
n := list.Len()
out := make(chan algoContainer)
go func () {
for i := 0; i < n; i++ {
result := list.Copy()
// actually useful:
if result.Less(n-1, 0) {
result.Swap(n-1, 0)
}
out <- result
}
close(out)
}()
return out
}
Run Code Online (Sandbox Code Playgroud)
由于Go编程语言目前不支持泛型类型,因此这很难做到.
可能会在某些时候添加泛型.尽管我们了解一些程序员,但我们对他们并不感到紧迫.
泛型很方便,但它们在类型系统和运行时的复杂性方面付出了代价.我们还没有找到一种能够与复杂性成比例的设计,尽管我们会继续考虑它.同时,Go的内置映射和切片,以及使用空接口构造容器(具有显式拆箱)的能力意味着在许多情况下可以编写执行泛型将启用的代码,如果不太顺利的话.
这仍然是一个未决问题.
通过使用Len,Less和Swap方法定义sort.Interface类型,查看Go sort包以查看它如何处理特定于类型的比较和其他操作.
Go没有泛型类型,但您可以查看sort如何找到解决方法.他们做的是创建一个这样的界面:
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
Run Code Online (Sandbox Code Playgroud)
现在,对于任何自定义类型,您都可以创建可以排序的相应自定义集合类型.排序算法只需要处理整数和布尔值,因此不会看到或关心底层数据类型是什么.