Оператор type позволяет определять именнованный тип на основе другого. Например:
type mile uint
В данном случае определяется именованный тип mile, который основывается на типе uint. По сути mile представляет тип uint и работа с ним будет производиться также, как и с типом uint. Однако в то же время фактически это новый тип.
Мы можем определять переменные данного типа, работать с ними как с объектами базового типа uint:
package main import "fmt" type mile uint func main() { var distance mile = 5 fmt.Println(distance) distance += 5 fmt.Println(distance) }
Но может возникнуть вопрос, а зачем это нужно, зачем определять именнованный тип, если он все равно ведет себя как тип uint? Рассмотрим следующую ситуацию:
package main import "fmt" type mile uint type kilometer uint func distanceToEnemy (distance mile){ fmt.Println("расстояние для противника:") fmt.Println(distance, "миль") } func main() { var distance mile = 5 distanceToEnemy(distance) // var distance1 uint = 5 // distanceToEnemy(distance1) // !Ошибка // var distance2 kilometer = 5 // distanceToEnemy(distance2) // ! ошибка }
Здесь определены два именнованных типа: mile и kilometer, которые по сути представляют тип uint и которые предназначены для выражения расстояния в милях
и километрах соответственно. И также определена функция distanceToEnemy()
, которая отображает расстояние в милях до условного противника.
В качестве параметра принимает значение mile - именно значение типа mile, а не типа uint. Это позволит нам уменьшить вероятность передачи некорректных данных. То есть
передаваемые данные должны быть явным образом определены в программе как значение типа mile, а не типа uint или типа kilometer. Два именнованных типа считаются разными, даже
если они основаны на некотором общем типе (как uint в данном случае).
Также именнованные типы позволяют придать типу некоторый дополнительный смысл. Так, использование в коде типа "kilometer" или "mile" позволит указать на предназначение переменной или параметра и
будет более описательным, чем просто тип uint
.
Еще одна ситуация, где можно применять именнованные типы - это сокращение названия типов в том случае, если они слишком длинные или громоздкие. Например, рассмотрим следующий пример:
package main import "fmt" func action(n1 int, n2 int, op func(int, int) int){ result := op(n1, n2) fmt.Println(result) } func add(x int, y int) int { return x + y } func main() { var myOperation func(int, int) int = add action(10, 25, myOperation) // 35 }
Здесь определена функция action, которая принимает два числа и некоторую другую функцию с типом func(int, int) int
- то есть функцию, которая принимает два числа и также возвращает число.
В функции main определяется переменная myOperation, которая как раз представляет функцию типа func(int, int) int
, получает ссылку на функцию add и
передается в вызов action(10, 25, myOperation)
Теперь определим именнованный тип для типа func(int, int) int
:
package main import "fmt" type BinaryOp func(int, int) int func action(n1 int, n2 int, op BinaryOp){ result := op(n1, n2) fmt.Println(result) } func add(x int, y int) int { return x + y } func main() { var myOperation BinaryOp = add action(10, 35, myOperation) // 45 }
Теперь тип функции func(int, int) int
проецируется на именнованный тип BinaryOp, который представляет бинарную операцию над двумя операндами:
type BinaryOp func(int, int) int
Такое название короче оригинального определения типа и в то же время является более описательным (по крайней мере для меня). Соответственно далее его можно использовать для указания типа параметра:
func action(n1 int, n2 int, op BinaryOp){ ... }
или переменной:
var myOperation BinaryOp = add
На именнованные типы похожи псевдонимы. Они также определяются с помощью оператора type, только при присвоении типа применяется операция присваивания:
type псевдоним = имеющийся_тип
Однако псевдоним НЕ определяет нового типа и все псевдонимы одного и того же типа считаются идентичными. Например:
package main import "fmt" type mile = uint type kilometer = uint func distanceToEnemy (distance mile){ fmt.Println("расстояние для противника:") fmt.Println(distance, "миль") } func main() { var distance mile = 5 distanceToEnemy(distance) var distance1 uint = 5 distanceToEnemy(distance1) // норм var distance2 kilometer = 5 distanceToEnemy(distance2) // норм }
Здесь для типа uint определяются два псевдонима - mile и kilometer. И несмотря на то, что параметр функции distanceToEnemy определен как параметр типа mile, ему можно передать и значение собственно типа uint, и значение его псевдонима - kilometer.
Обычо псевдонимы применяются для сокращения названий других типов или для определения более описательного имени.