Зачем из функции делать тип и как это работает?

У меня есть следующий пример использования функции как типа:

type testInt func(int) bool

func isOdd(integer int) bool {
    if integer%2 == 0 {
        return false
    }
    return true
}

func isEven(integer int) bool {
    if integer%2 == 0 {
        return true
    }
    return false
}

// передаем функцию `f` как аргумент в другую функцию

func filter(slice []int, f testInt) []int {
    var result []int
    for _, value := range slice {
        if f(value) {
            result = append(result, value)
        }
    }
    return result
}

func main() {
    slice := []int{1, 2, 3, 4, 5, 7}
    fmt.Println("Срез = ", slice)
    odd := filter(slice, isOdd) // используем функции как значения
    fmt.Println("Нечетные элементы среза: ", odd)
    even := filter(slice, isEven)
    fmt.Println("Четные элементы среза: ", even)
}

Получается что мы передаём функции isOdd и isEven как значение (то есть передали данные которые должны выйти из функции. В данном примере - true/false), но какую роль тогда играет у нас конструкция type testInt func(int) bool ?
Ещё хотелось бы узнать где зачастую используется такие конструкции?


Ответы (1 шт):

Автор решения: Komdosh

type testInt func(int) bool - подобие интерфейса с единственной функцией (функциональный интерфейс в Java). Фактически вы объявляете тип функции, которую можно будет использовать как в качестве переменной или аргумента другой функции.

В представленном примере, вы сообщаете компилятору, что тип testInt является функцией, которая принимает единственный аргумент типа int и возвращает тип bool. Другими словами функция, которая была передана в качестве аргумента типа testInt должна соответствовать заявленному интерфейсу (принимать одно целое число и возвращать булевое значение).

Ваши функции isOdd и isEven удовлетворяют этому интерфейсу, так что они могут быть использованы в качестве аргумента функции filter. Если вы определите функцию как func isEven(integer float64) bool и попытаетесь передать её в качестве аргумента в filter, то будет ошибка компиляции с указанием того, что функция не соответствует типу testInt

cannot use isEven(type func(float64) bool) as type testInt

Когда вы передаёте isOdd, isEven в функцию filter вы получаете указатель на функцию, что позволяет вам подставлять различные реализации действий над данными, которые вы передали в filter. Это сокращает код, так как у вас в функции филтра заложена логика действий над коллекцией элементов, а непосредственное поведение над каждым объектом (в данном примере проверка на необходимое условие) вы передаёте во время вызова данной функции.

→ Ссылка