На этом шаге рассмотрим встраиваивание интерфейсов в Go.
Интерфейсы в языке Go обладают поддержкой встраивания. Интерфейсы могут встраиваться в другие интерфейсы, это значит, что сигнатуры методов во встраиваемом интерфейсе доступны в интерфейсе, куда он встраивается. Эту особенность иллюстрирует следующий простой пример.
/* Интерфейс ВВерхнийРегистр определяет единственный метод LowerCase(), не имеющий аргументов и ничего не возвращающий*/ type ВВерхнийРегистр interface{ ВерхнийРегистр() } //Интерфейс ВНижнийРегистр объявлен аналогично type ВНижнийРегистр interface{ НижнийРегистр() } /*Интерфейс ПреобразоватьРегистр встраивает два интерфейса. Чтобы конкретный тип удовлетворял требованиям интерфейса ПреобразоватьРегистр, он должен иметь методы ВерхнийРегистр() и НижнийРегистр()*/ type ПреобразоватьРегистр interface{ ВВерхнийРегистр /* Как если бы был объявлен метод ВерхнийРегистр()*/ ВНижнийРегистр /* Как если бы был объявлен метод НижнийРегистр()*/ } }
Если в первые два интерфейса добавить дополнительные методы (например, ОсобыйВерхнийРегистр() и ОсобыйНижнийРегистр()), интерфейс ПреобразоватьРегистр автоматически включил бы их без изменения его определения.
Добавим два новых интерфейса:
type СПрописной interface{ ПерваяПрописная() } type ИзменитьРегистр interface{ ИзменитьРегистр /* Как если бы были объявлены методы ВерхнийРегистр() и НижнийРегистр()*/ СПрописной /* Как если бы был объявлен метод ПерваяПрописная()*/ }
в результате получилась иерархия встроенных интерфейсов как показано на рис. 1
Рис.1. Иерархия встроенных интерфейсов
Для использования интерфейсов, их нужно реализовать в конкретных типах.
func(part *Part) ПерваяПрописная() { part.Name = НачатьСПрописной(part.Name) }
В пользовательский тип Part добавим дополнительный метод ПерваяПрописная(), который воздействует на поле Name, подобно методам LowerCase() и UpperCase(). Все методы, изменяющие регистр символов, требуют передачи приемника по указателю, потому что изменяют само значение, относительно которого вызываются. Методы LowerCase() и UpperCase() реализованы с использованием функций из стандартной библиотеки, а метод ПерваяПрописная() с помощью пользовательской функции НачатьСПрописной().
func НачатьСПрописной(s string) string { var chars []rune upper := true for _, char := range s { if upper { char = unicode.ToUpper(char) } else { char = unicode.ToLower(char) } chars = append(chars, char) upper = unicode.IsSpace(char) || unicode.Is(unicode.Hyphen, char) } return string(chars) }
Архив с примером можно взять здесь.
Функция возвращает копию переданной ей строки, где все символы преобразованы в нижний регистр, кроме самого первого и первых символов после пробелов или дефисов, которые преобразуются в верхний регистр.
На следующем шаге продолжим рассматривать встраивание интерфейсов в Go.