Шаг 97.
Язык программирования Go.
Встраивание интерфейсов в структурах

    На этом шаге мы рассмотрим встраивание интерфейсов в Go.

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

    Рассмотрим пример, демонстрирующий, как можно организовать поддержку параметров командной строки, имеющих короткие и длинные имена (например, "-o" и "--outfile") и принимающих значения определенных типов (int, float64, string), а также некоторых общих методов.

/*Интерфейс Optioner определяет общие методы для всех типов параметров,
поддержку которых требуется реализовать*/
type Optioner interface  {
	Name() string
	IsValid() bool
}
/*Структура OptionCommon имеет два поля, общих для всех параметров*/
type OptionCommon struct {
	ShortName string
	LongName  string 
}
/*Реализация типа IntOption и неэкспортируемой функции name(). Благодаря встраиванию
структуры OptionCommon появляется возможность обращаться к ее полям непосредственно,
как это делается в методе IntOption.Name(). Структура IntOption удовлетворяет
требованиям интерфейса Optioner (поскольку предоставляет методы Name() и IsValid()
с требуемыми сигнатурами)*/
type IntOption struct {
	OptionCommon        // Анонимное поле (встраивание)
	Value, Min, Max int // именованное поле (агрегирование)
}
func (option IntOption) Name() string {
	return name(option.ShortName, option.LongName)
}
func (option IntOption ) IsValid() bool {
	return  option.Min <= option.Value && option.Value <= option.Max
}
/*Функция name() реализована в отдельной функции, что дает возможность
использовать эту функцию в других типах параметров*/
func name(shortName, longName string) string {
	if longName == "" {
		return shortName
	}
	return longName
}
/*Пример создания и использования значения типа IntOption*/
func main() {
//----------------------------------
/*В переменной topOption типа IntOption можно присвоить значение только полям
OptionCommon и Max, т.к. для других полей (Value и Min) подходят и нулевые значения.
В языке Go допускается создавать структуры и инициализировать только отдельные поля,
используя синтаксис имяПоля: значениеПоля. Всем полям, не инициализированным явно,
автоматически присваиваются соответствующие нулевые значения*/
  topOption := IntOption{
            OptionCommon: OptionCommon{"t", "top"},
            Value:        45,
	    Min:          10,
	    Max:          100,
  }
//----------------------------------
/*Относительно переменной option можно вызывать любые методы,
определяемые интерфейсом Optioner, как это сделано в теле цикла,
где вызываются методы Option.Name() и Option.IsValid()*/
  for _, option := range []Optioner{topOption} {
        fmt.Print("name=", option.Name(), " • valid=", option.IsValid())
        fmt.Print(" • value=")
        switch option := option.(type) { // затеняющая переменная
              case IntOption:
		    fmt.Print(option.Value, " • min=", option.Min,
				" • max=", option.Max, "\n")
//----------------------------------
		}
	}
}  

    На следующем шаге продолжим рассматривать пример встраивания интерфесов в структурах.


Предыдущий шаг Содержание Следующий шаг