在go中使用"泛型"

[2012-05-21 翻译自这里, 对原文有所扩展, 也有所删减. 版权属于原作者, 转载必须保留此声明.]

在进入泛型的话题之前, 首先实现对int slice(可以看做int数组)的冒泡排序:
func BubbleSort(array []int) {
    for i := 0; i < len(array); i++ {
        for j := 0; j < len(array)-i-1; j++ {
            if array[j] > array[j+1] {
                // 交换
                array[j], array[j+1] = array[j+1], array[j]
            }
        }
    }
} 
如你所见, 上面的代码仅适用于对int数组进行排序, 如果想要对string数组排序, 不得不另写一个. 
是否可以只写一个通用的泛型程序, 以便对所有类型的数组(甚至是任意数据)进行冒泡排序?

很遗憾, go不支持java中的标记式泛型. 但是我们可以使用go的interface实现类似的功能.
interface用于定义方法的集合. 在冒泡排序中, 我们可以将排序操作分解成3个方法: Len()方法负责计算长度, Less(i, j)方法负责比较大小, Swap(i, j)方法负责进行交换.
// 定义可排序接口
type Sortable interface {
    Len() int
    Less(int, int) bool
    Swap(int, int)
}
可以说, 任何实现了Sortable接口的数据类型都可进行冒泡排序, 下面是对Bubblesort方法的改造:
func BubbleSortable(arr Sortable) {
    length := arr.Len()
    for i := 0; i < length; i++ {
        for j := i; j < length-i-1; j++ {
            if arr.Less(j, j+1) {
                arr.Swap(j, j+1)
            }
        }
    }
} 
BubbleSortable函数可以对所有Sortable类型的数据进行排序. 那么, 哪些数据是Sortable类型的呢? 很简单, 那些实现了Len(), Less(i, j), Swap(i, j)方法的数据类型都是Sortable的. 

如果想要对int数组进行冒泡排序, 只需让int数组实现以上3个方法即可:
// 定义IntArr类型
type IntArr []int
// 给IntArr提供Len方法
func (arr IntArr) Len() int {
    return len(arr)
}
// 给IntArr提供Less方法
func (arr IntArr) Less(i int, j int) bool {
    return arr[i] < arr[j]
}
// 给IntArr提供Swap方法
func (arr IntArr) Swap(i int, j int) {
    arr[i], arr[j] = arr[j], arr[i]
} 
至此, 我们定义了新的类型: IntArr(实际上就是int数组), 并为IntArr增加了Len, Less, Swap方法.
注意, 在go中, 实现接口不需要像java那样显式的说明对某个接口的implements, 只需要为类型提供所有interface中定义的方法即可. 此例中, 我们给IntArr提供了所有Sortable中定义的方法, 所以IntArr已经实现了Sortable接口. 接下来要做的是将IntArr类型的数据传递给BubbleSortable函数就可以了:
intarr := IntArr{2, 3, 1, -9, 0}
// 调用排序方法
BubbleSortable(intarr)
// 输出排序之后的数据
fmt.Printf("sorted int arr is: %v\n", intarr)
 
同样的, 如果想对string数组进行冒泡排序, 也只需要让string数组实现Sortable接口中定义的所有方法:
type StrArr []string
func (arr StrArr) Len() int {
    return len(arr)
}
func (arr StrArr) Less(i int, j int) bool {
    return arr[i] < arr[j]
}
func (arr StrArr) Swap(i int, j int) {
    arr[i], arr[j] = arr[j], arr[i]
} 
测试代码如下:
strarr := StrArr{"nut", "ape", "elephant", "zoo", "go"}
Bubblesort(strarr)
fmt.Printf("sorted string arr is: %v\n", strarr)
 
现在, 你可以对任意数据进行冒泡排序了, 只需要该类型实现了Len, Less, Swap方法.
### 回答1: Golang 是支持的,所以你使用。但是你可以使用类似于方法实现类似的效果。 你可以使用 interface{} 类来表示任何类。例如: ``` func Print(a interface{}) { fmt.Println(a) } ``` 这样就可以使用 Print 函数输出任何类的值了。 你也可以使用反射来实现类似的效果。例如: ``` func Print(a interface{}) { v := reflect.ValueOf(a) fmt.Println(v) } ``` 这样就可以使用 Print 函数输出任何类的值了。 你也可以使用模板函数来实现类似的效果。例如: ``` func Print(a interface{}) { t := template.Must(template.New("").Parse("{{.}}")) t.Execute(os.Stdout, a) } ``` 这样就可以使用 Print 函数输出任何类的值了。 希望这对你有帮助。 ### 回答2: 截至2021年1月,Go语言(Golang)尚具备内建的机制,即没有直接的方法来创建通用的数据结构和算法。然而,Go社区一直在探索如何在缺少的情况下实现通用性。 在没有的情况下,开发者通常采用特定类接口(interface{})或类断言(type assertion)来实现类似的效果。使用接口可以定义通用的函数签名,使函数能够接受多种类参数。同时,使用断言可以在运行时检查参数的实际类,并进行相应的处理。 此外,Go语言还提供了一些通用的数据结构和算法库,如container包中的List、HashMap等。通过在这些数据结构和算法中使用interface{}类,并利用类断言来确保类的正确性,可以实现相对通用的功能。 Go语言的开发团队也一直在推动的研究和开发。在2022年将发布的Go 1.18版本中,预计将加入的支持。该特性将为开发者提供使用更为简洁和安全的方式来创建通用的数据结构和算法。 总之,目前在Go语言中还没有内建的机制,但可以通过接口和类断言来实现类似的功能。此外,Go语言的开发者正在努力研发并计划在未来的版本中添加支持。 ### 回答3: 目前(截至2021年),Go语言(Golang)尚支持原生,这意味着在编写Go代码时,无法直接声明方法。然而,Go社区一直在积极探索和讨论如何实现,有一些可选方案可以用来模拟使用。 其中,最常见的一种方法使用接口实现。通过创建一个接口并在函数签名或结构体中使用接口作为参数或字段,可以实现对各种类的参数和字段的通用操作。这种方法虽然可以达到类似的效果,但在类实参和类断言方面存在一些限制和复杂性。 另一种方法使用代码生成工具模拟。通过在编译时使用代码生成工具,可以根据同的类参数生成特定的代码,并将其插入到源代码中。这种方式可以实现在编译时生成针对同类的特定代码,从而实现类似的效果。但是,这种方法需要使用额外的工具和开发流程,并且会增加代码的复杂性。 除了这些方法外,Go社区还在断探索其他更为原生的实现方式,例如Go2的设计,该设计目前正在积极开发中。Go2通过添加函数的直接支持,将大大简化使用的过程,并提供更好的类安全和可读性。尽管Go2还未正式发布,但对于在项目中使用的需求,可以关注最新的Go官方进展和社区讨论。 总的来说,目前在Go语言中,尚支持原生的,但可以使用接口或代码生成工具等方式来模拟使用。未来,随着Go2的正式发布,将会提供更为便捷和直接的方式来使用。环境和项目需求决定了选择合适的方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值