Интерфейсы в Go предоставляют способ указать поведение объекта: если что-то может сделать это, тогда это можно использовать здесь. В предыдущих постах мы уже рассматривали пару простых примеров; пользовательские принтеры могут быть реализованы методом String
, в то время как Fprintf
может генерировать вывод для чего угодно с помощью метода Write
. Интерфейсы только с одним или двумя методами распространены в коде Go и обычно им дается имя, полученное из метода, например io.Writer
для чего-то, который реализует Write
.
Тип может реализовывать несколько интерфейсов. Например, коллекция может быть отсортирована с помощью процедур в пакете sort
, если он реализует sort.Interface
, который содержит Len()
, Less(i, j int) bool
и Swap(i, j int)
, и он также может иметь собственный кастомный форматтер. В этом надуманном примере Sequence
удовлетворяет обоим условиям.
type Sequence []int
// Методы требуемые sort.Interface.
func (s Sequence) Len() int {
return len(s)
}
func (s Sequence) Less(i, j int) bool {
return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// Метод для печати - сортирует элементы перед печатью.
func (s Sequence) String() string {
sort.Sort(s)
str := "["
for i, elem := range s {
if i > 0 {
str += " "
}
str += fmt.Sprint(elem)
}
return str + "]"
}
Преобразования
Метод String
в Sequence
воссоздает работу, которую Sprint
уже выполняет для срезов. Мы можем поделить усилия, если мы преобразуем Sequence
в обычный []int
перед вызовом Sprint
.
func (s Sequence) String() string {
sort.Sort(s)
return fmt.Sprint([]int(s))
}
Этот метод является еще одним примером техники преобразования для вызова Sprintf
безопасно из метода String
. Поскольку два типа (Sequence
и []int
) одинаковы, если мы игнорируем имя типа, это допустимо проводить преобразование между ними. Преобразование не создает новое значение, оно просто временно действует как будто существующее значение имеет новый тип. (Существуют и другие допустимые преобразования, например, из целого числа в число с плавающей запятой, чтобы создать новое значение.)
Это идиома в Go программах - преобразовывать тип выражения для доступа к другому набору методов. В качестве примера мы могли бы использовать существующий тип sort.IntSlice
, чтобы уменьшить весь пример:
type Sequence []int
// Метод для печати - сортирует элементы перед печатью.
func (s Sequence) String() string {
sort.IntSlice(s).Sort()
return fmt.Sprint([]int(s))
}
Теперь вместо Sequence
реализуем несколько интерфейсов (сортировка и печать), мы используем возможность элемента данных быть преобразованными в несколько типов (Sequence
, sort.IntSlice
и []int
), каждый из которых выполняет определенную часть работы. Это более необычно на практике, но может быть эффективным.
Читайте также:
Комментариев нет:
Отправить комментарий