Golang: как работает тип func?

Если в golang нам приспичит сделать closure, мы напишем:
closureFunc := func () someReturnType {
  /* function body */
  return valueOfSomeReturnType;
}

Переменная closureFunc будет иметь в этом случае тип:
func () someReturnType
Итак, если я напишу, например, такой пассаж:
package main
import "fmt"
type SoneFuncType func() bool
func main() {
  var someInstance SomeFuncType
  fmt.Printf("%+v",someInstance);
}

Это все компилятор спокойно скомпилирует.

Теперь суть вопроса:

Если в первом варианте тело функции было явно задано сразу, то как быть во втором варианте? Несколько минут экспериментов с разными написаниями результата не дали. Да и вообще, каков тогда смысл давать возможность объявить такой тип явно, через type keyword?

Словом, предлагайте варианты, господа. Только не спрашивайте, зачем мне это, чисто академический интерес =)
  • Вопрос задан
  • 5731 просмотр
Решения вопроса 1
Tyranron
@Tyranron
Во втором варианте вроде как так. Чтобы объявить тело функции, нужно использовать ключевое слово func и никак иначе, что разумно по своим причинам. Как минимум, Вам не нужно помнить и держать в голове какая сигнатура кроется за каким типом, когда Вы смотрите на тело функции, то есть для каждого тела функции видно явно что оно должно принимать и возвращать. К тому же, дополнительная гибкость (в данном случае: объявление функции через алиасы типов, а не ключевое слово func) - это всегда удар по производительности, в данном случае - вероятное повышении времени компиляции, а для разработчиков языка это один из главных факторов, потому они очень и очень придирчиво относятся ко всем введениям и возможностям компилятора. Вон, от них даже дженериков никак допроситься не могут. Более того, выгода от возможности объявлять тело функции через алиасы типов (type aliases), а не ключевое слово func, крайне сомнительна, Вам так не кажется? К тому же не стоит путать объявление типа и объявление функции. Логично, что всегда сначала должен быть объявлен тип, а потом уже сама функция/переменная/структура, просто синтаксис языка позволяет сократить писанину. А Вы в данной ситуации хотите обойтись только созданием типа. А как тогда будете именовать входные параметры функции при её объявлении, если таковы имеются?

Выгода же абсолютно такая же, как и при других вариантах применения алиасов типов. В первую очередь - это возможность дополнительного контроля типов.
Например: Вы разрабатываете библиотеку (свой package) и Вам нужно, чтобы какая-то функция получала на вход только те функции, которые определены у Вас в библиотеке и никакие другие. Тогда Вы создаете алиас типа на сигнатуру функции и делаете его невидимым для внешних потребителей (объявляете с маленькой буквы).
package mylib

type someFunc func() bool

var (
	Apple someFunc = func() bool {
		return true
	}
	Dog someFunc = func() bool {
		return false
	}
)

func Consume(f someFunc) {
	f()
}

После этого внешний потребитель не сможет вызвать функцию Consume() передав туда какую угодно функцию, а только те функции, которые Вы ему приоткрыли.
package main

import "mylib"

func main() {
	externalFunc := func() bool {
		return true
	}
	
	mylib.Consume(externalFunc) 	// fail
	var extF mylib.someFunc		// fail
	
	mylib.Consume(mylib.Apple)	// success
}

Таким образом, обвязав свою библиотеку дополнительным контролем типов, Вы добились желаемого результата.
Во вторую очередь - это возможность сделать код более читаемым. Например, у Вас где-то есть достаточно громоздкая сигнатура и её нужно использовать во многих местах, чтобы не писать одно и то же много раз, Вы пишете сигнатуру только при объявлении функции и создании алиаса, а потом жонглируете алиасом.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
q1t
@q1t
для понимая этого советуют почитать - это

поиграться
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы