Общее программирование на Go?

Я знаю, что 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

Есть ли способ сделать это без такого количества избыточного кода?


person laurent    schedule 27.02.2013    source источник


Ответы (3)


Максимум, чего вы можете добиться, это использование типа 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

or

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

Однако это приведет к некоторым накладным расходам во время выполнения. Я бы лучше придерживался отдельных функций и пытался как-то реструктурировать код.

person Vladimir Matveev    schedule 27.02.2013
comment
Я отправил тот же совет одновременно :-) - person Thomas Kappler; 27.02.2013

Вот рабочий пример того, как вы можете изменить свой код.

Поскольку вы знаете, какой тип вы ожидаете для данного имени, вы можете написать свой метод Get в общем виде, возвращая interface{}, а затем утверждать тип на месте вызова. См. спецификацию об утверждениях типов.

Существуют разные способы эмуляции некоторых аспектов дженериков в Go. В списке рассылки было много дискуссий. Часто есть способ реструктурировать код, чтобы он меньше зависел от дженериков.

person Thomas Kappler    schedule 27.02.2013

В клиентском коде вы можете сделать так:

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
}
person mug896    schedule 04.12.2014