Метод-значение
Допустим, у нас есть сервер, который можно тыкать палочкой:
type Server struct {
nPings int
}
func (s *Server) Ping() {
s.nPings++
}
Давайте попингуем его вот так:
s := Server{}
ping := s.Ping // хм
ping()
ping()
ping()
Как думаете, что произойдет? Я задал этот вопрос на канале и получил такие ответы:
Что будет при таком вызове ping?
18% Ругань компилятора
■■■■
11% Паника в рантайме
■■
15% Паника у меня
■■■
56% Увеличится s.nPings
■■■■■■■■■■■
Действительно, метод у значения структуры (или указателя на значение) — это просто функция с конкретным получателем (тем самым значением структуры). Такой метод-значение (method value) можно использовать как обычную функцию — вызывать напрямую или передавать в качестве параметра, например.
Предположим, у нас есть тип-монитор, который умеет периодически проверять доступность сервиса, ведет историю проверок, считает процент доступности и выполняет другие полезные действия.
Монитору совершенно не нужно знать о конкретной реализации сервиса. Достаточно получить в конструкторе функцию-пинг, и дальше вызывать ее:
type Monitor struct {
ping func() error
// ...
}
func NewMonitor(ping func() error) *Monitor {
return &Monitor{ping}
}
И если у нашего сервера есть подходящий по сигнатуре метод:
func (s *Server) Ping() error {
// ...
}
То можно прямо его и передать без всяких оберток:
s := Server{}
m := NewMonitor(s.Ping)
Такие вот элементы функционального программирования в глубоко процедурном языке :)
★ Подписывайтесь на новые заметки.