6

我知道 Go 不支持模板或重载函数,但我想知道是否有任何方法可以进行某种泛型编程?

我有很多功能,例如:

func (this Document) GetString(name string, default...string) string {
    v, ok := this.GetValueFromDb(name)
    if !ok {
        if len(default) >= 1 {
            return default[0]
        } else {
            return ""
        }
    }
    return v.asString
}

func (this Document) GetInt(name string, default...int) int {
    v, ok := this.GetValueFromDb(name)
    if !ok {
        if len(default) >= 1 {
            return default[0]
        } else {
            return 0
        }
    }
    return v.asInt
}

// etc. for many different types

有没有办法做到这一点而没有那么多冗余代码?

4

3 回答 3

12

您可以实现的大部分是interface{}类型的使用,如下所示:

func (this Document) Get(name string, default... interface{}) interface{} {
    v, ok := this.GetValueFromDb(name)
    if !ok {
        if len(default) >= 1 {
            return default[0]
        } else {
            return 0
        }
    }
    return v
}

GetValueFromDb还应该调整函数以返回interface{}值,而不是像现在这样的包装器。

然后在客户端代码中,您可以执行以下操作:

value := document.Get("index", 1).(int)  // Panics when the value is not int

或者

value, ok := document.Get("index", 1).(int)  // ok is false if the value is not int

不过,这会产生一些运行时开销。我最好坚持使用单独的函数并尝试以某种方式重组代码。

于 2013-02-27T09:06:06.857 回答
3

这是一个如何更改代码的工作示例。

由于您知道给定名称的预期类型,您可以以通用方式编写 Get 方法,返回interface{},然后在调用站点断言类型。请参阅有关类型断言的规范。

有不同的方法可以在 Go 中模拟泛型的某些方面。邮件列表上有很多讨论。通常,有一种方法可以重组代码,从而减少对泛型的依赖。

于 2013-02-27T09:11:14.353 回答
0

在客户端代码中,您可以这样做:

res := GetValue("name", 1, 2, 3)
// or
// res := GetValue("name", "one", "two", "three")

if value, ok := res.(int); ok {
    // process int return value
} else if value, ok := res.(string); ok {
    // process string return value
}

// or
// res.(type) expression only work in switch statement
// and 'res' variable's type have to be interface type
switch value := res.(type) {
case int:
    // process int return value
case string:
    // process string return value
}
于 2014-12-04T03:32:26.330 回答