Шаг 99.
Язык программирования Go.
Пример. Пользовательский тип с единственным значением

    На этом шаге мы начнем рассматривать пример создания и реализации пользовательского типа с единственным значением.

    Рассмотрим пример реализации для представления логических значений с использованием вещественных чисел: 0.0 – для значения false и 1.0 – для значения true, 0.5 означает 50% истины (50% лжи), значение 0.25 означает 25% истины (75% лжи) и т. д.

    Разрабатываемый тип называется NLogic. Сначала рассмотрим определение самого типа:

//Тип NLogic основан на структуре, содержащей единственное поле типа float32
type NLogic struct{ val float32 } 

    Поле val является неэкспортируемым, поэтому для создания значений типа NLogic в пакетах, импортирующих пакет nlogic, необходимо использовать функцию-конструктор New() в соответствии с соглашениями, принятыми в языке Go, тем самым мы можем гарантировать создание допустимых значений типа NLogic.

func New(val interface{}) (*NLogic, error) {
	v, err := float32ForValue(val)
	return &NLogic{v}, err
}

    Функция New() возвращает указатель на значение типа NLogic. Это означает, что методам, изменяющим значение типа NLogic (метод Set()), приемник должен передаваться по указателю, а не по значению. Указатели лучше подходят для работы с большими составными типами (например, с двумя и более полями), чтобы их значения можно было передавать в виде одного простого указателя.

    При работе с типом NLogic инициализировать новые значения этого типа можно не только значениями типа float32, но и значениями типа float64, int и bool. Это достигается за счет использования собственной функции float32ForValue(), возвращающей значение типа float32 и nil для указанного значения, или 0.0 и значение типа error, если функции было передано значение неподдерживаемого типа.

func float32ForValue(val interface{}) (log float32, err error) {
   switch  val := val.(type) {
      case float32:
		log = val
      case float64:
		log = float32(val)
      case int:
		log = float32(val)
      case bool:
		log = 0
		if val {
			log = 1
		}
      default:
		return 0, fmt.Errorf("float32ForValue(): %v не является "+
			"числом или логическим значением", val)
   }
   if log < 0 {
      log = 0
   } else if log > 1 {
      log = 1
   }
   return log, nil
}

    Эта неэкспортируемая вспомогательная функция используется методом New() для преобразования значения val в значение типа float32 в диапазоне [0.0, 1.0]. Обработка исходных значений различных типов реализуется с помощью инструкции switch выбора по типу.

    Если функции передается значение недопустимого типа, она возвращает непустое значение типа error. Это позволяет вызывающей программе проверить возвращаемое значение и предпринять необходимые действия в случае появления ошибки. Вызывающая программа может возбудить аварийную ситуацию и вызвать крах приложения с выводом трассировочной информации или как-то иначе решить проблему. В низкоуровневых функциях, подобных этой, часто лучше просто возвращать признак ошибки, чтобы сообщить о проблеме, потому что они не обладают достаточной информацией о логике работы приложения и о том, как следует обрабатывать ошибку, тогда как вызывающая программа находится в лучшем положении и знает, какие действия следует предпринять.

    Передача значения недопустимого типа является программной ошибкой, следовательно, нужно возвращать непустое значение типа error, для значений допустимых типов вне допустимого диапазона производить преобразование в ближайшее допустимое значение.

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

    Функцию-конструктор nlogic.New() можно рассматривать как функцию преобразования типа, поскольку она может принимать значения типов float32, float64, int и bool, и возвращает значение типа *NLogic. Два метода, приведенные ниже, выполняют обратные преобразования.

func (log *NLogic) Bool() bool {
	return log.val >= .5
}
func (log *NLogic) Float() float64 {
	return float64(log.val)
}


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