[英]making generic algorithms in go
我想不出一種干凈的方法來實現適用於任何類型的算法。
以下代碼在嘗試將字符串或類型化切片轉換為接口時會產生錯誤,並且無法比較 interface{} 對象: 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
}
雖然很痛苦(我認為它應該是自動的),但我可以手動將鍵入的切片裝箱和拆箱到 interface{} 中,上面真正的問題是比較。 它只是變得越來越笨拙。
a := [3]int{1,2,3}
b := make([]interface{}, len(a))
for i, _ := range a {
b[i] = a[i]
}
我什至想過使用vector.Vector,但是很多人說永遠不要使用它們。
那么我應該為 int 切片和字符串實現相同的算法嗎? myObject 的切片呢? 我可以使用自定義比較函數制作一個接口,但是如何使它與標准類型一起使用?
您可以使用接口在 Go 中執行此操作。 采用接口類型的 function 是通用的,因為它不關心底層具體類型的數據表示。 它通過方法調用完成所有工作。
然后,要制作算法的通用版本,您必須確定算法所需的數據對象的所有功能,並且您必須定義抽象這些功能的方法。 抽象方法簽名成為接口的方法集。
要使類型與這種泛型算法兼容,您需要在類型上定義方法以滿足算法參數的接口。
我將采用您的示例代碼並展示一種方法來做到這一點。 大多數必需的功能恰好被 sort.Interface 覆蓋,所以我選擇嵌入它。 只需要一項其他功能,即制作數據副本。
type algoContainer interface {
sort.Interface
Copy() algoContainer
}
以下是由您的示例代碼制作的完整工作程序。
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
}
由於 Go 編程語言目前不支持泛型類型,這將很難做到。
Generics 可能會在某個時候添加。 我們不覺得他們有緊迫感,盡管我們知道一些程序員會這樣做。
Generics 很方便,但它們的代價是類型系統和運行時的復雜性。 盡管我們仍在繼續思考,但我們還沒有找到一種能夠提供與復雜性成比例的價值的設計。 同時,Go 的內置映射和切片,以及使用空接口構造容器(通過顯式拆箱)的能力,意味着在許多情況下,即使不太順利,也可以編寫 generics 將啟用的代碼。
這仍然是一個懸而未決的問題。
查看 Go排序 package以了解它如何通過使用 Len、Less 和 Swap 方法定義sort.Interface類型來處理特定於類型的比較和其他操作。
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)
}
現在,對於任何自定義類型,您都可以制作相應的可排序的自定義集合類型。 排序算法只需要處理整數和布爾值,因此不會看到或關心底層數據類型是什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.