[Golang]通过interface实现"泛型"的用例

目前Golang最新版本为1.9, 暂时不支持泛型。
不过可以通过interface实现”泛型编程”效果, 下面以slice类型数据的添加/删除元素为例,
供大家参考一下:

package main

import (
    "errors"
    "fmt"
)

var (
    ERR_ELEM_EXISTS     = errors.New("element exits.")
    ERR_ELEM_NOT_EXISTS = errors.New("element not exits.")
)

// 定义切片,支持interface{}类型
// 假设该slice不支持存储相同元素
type SomeSlice []interface{}

// 初始化slice实例
func NewSomeSlice() SomeSlice {
    return make(SomeSlice, 0)
}

// 定义一个用于对比的接口
type Comparable interface {
    IsEqual(a interface{}) bool
}

// 定义struct类型
type Employee struct {
    Id   int32
    Name string
}

// Employee类型实现了Comparable接口
func (em Employee) IsEqual(b interface{}) bool {
    if em2, ok := b.(Employee); ok {
        return em.Id == em2.Id
    } else {
        return false
    }
}

// isEqual函数用于各种类型之间的比较
func isEqual(a, b interface{}) bool {
    if cmpa, ok := a.(Comparable); ok {
        return cmpa.IsEqual(b)
    } else if cmpb, ok := b.(Comparable); ok {
        return cmpb.IsEqual(a)
    } else {
        return a == b
    }
}

// 向slice添加元素
func (ss *SomeSlice) Add(elem interface{}) error {
    for _, v := range *ss {
        if isEqual(v, elem) {
            fmt.Printf("[Error]Cannot add the same element: %v\n", elem)
            return ERR_ELEM_EXISTS
        }
    }
    *ss = append(*ss, elem)
    return nil
}

//从slice中删除元素
func (ss *SomeSlice) Remove(elem interface{}) error {
    for k, v := range *ss {
        if isEqual(v, elem) {
            if k == len(*ss)-1 {
                *ss = (*ss)[:k]
            } else {
                *ss = append((*ss)[:k], (*ss)[k+1:]...)
            }
            return nil
        }
    }
    fmt.Printf("[Error]No such element: %v\n", elem)
    return ERR_ELEM_NOT_EXISTS
}

func main() {
    // 初始化slice
    slice := NewSomeSlice()

    // 正常情况下添加不同类型元素
    slice.Add(5)
    slice.Add("huahua")
    slice.Add(Employee{Id: 123, Name: "xiaohong"})
    slice.Add(10)
    slice.Add("xiaoming")
    slice.Add(Employee{Id: 456, Name: "xiaogang"})
    fmt.Println("After Add, Current Slice:", slice)

    // 添加了重复的元素
    slice.Add(10)
    slice.Add("huahua")
    slice.Add(Employee{Id: 456, Name: "xiaogang"})
    fmt.Println("After invalid Add, Current Slice:", slice)

    // 正常情况下删除元素
    slice.Remove(5)
    slice.Remove("huahua")
    slice.Remove(Employee{Id: 456, Name: "xiaogang"})
    fmt.Println("After Remove, Current Slice:", slice)

    // 删除并不存在的元素
    slice.Remove(11)
    slice.Remove("somename")
    slice.Remove(Employee{Id: 789, Name: "dajiu"})
    fmt.Println("After invalid Remove, Current Slice:", slice)
}

运行结果如下所示:

pintai@MG:~/src$ go run tmpl.go
After Add, Current Slice: [5 huahua {123 xiaohong} 10 xiaoming {456 xiaogang}]
[Error]Cannot add the same element: 10
[Error]Cannot add the same element: huahua
[Error]Cannot add the same element: {456 xiaogang}
After invalid Add, Current Slice: [5 huahua {123 xiaohong} 10 xiaoming {456 xiaogang}]
After Remove, Current Slice: [{123 xiaohong} 10 xiaoming]
[Error]No such element: 11
[Error]No such element: somename
[Error]No such element: {789 dajiu}
After invalid Remove, Current Slice: [{123 xiaohong} 10 xiaoming]

上面的例子实现了支持不同类型元素的slice,通过Add/Remove方法进行增删元素。
其中一个关键方法是isEqual, 对于实现了Comparable类型的对象使用了它的IsEqual方法来比较,对于其他类型(基础类型)数据则直接用 == 来进行比较。

猜你喜欢

转载自blog.csdn.net/moxiaomomo/article/details/78728050