Начнем кодить!!
Посмотрите на код ниже и подумайте, что он напечатает. [%T используется для печати информации о типе]
package main import "fmt" type int1 = int // OPTION-1 type int2 int // OPTION-2 func main() { var i1 int1 var i2 int2 fmt.Printf("%T, %T", i1, i2) }
Вывод
int, main.int2
Интересно, что i1 печатает int, а i2 печатает main.int2.
Почему мы видим этот результат?
i1 — это псевдоним. Псевдоним — это второе имя существующего типа, и это похоже на замену всех вхождений int1 на int.
Тогда как int2 — определение типа. Обратите внимание, что в выводе указано: «main.int2». Это означает, что int2 — новый тип.
Какая разница ?
Нам нужно посмотреть на это со следующих точек зрения:
- Поведение операций относительно нового типа
Мы хотим проверить, ведут ли новые типы точно так же, как исходный тип int. Для этого мы пробуем некоторые операции, поддерживаемые типом int.
package main import "fmt" type int1 = int // OPTION-1 type int2 int // OPTION-2 func main() { var i1 int1 var i2 int2 // Check if integer operations works i1 += 10 i2 += 10 i1 -= 5 i2 -= 5 // check if the new type needs an explicit type conversion var i3 int = i1 var i4 int = i2 fmt.Println(i1, i2, i3, i4) }
Вывод
./prog.go:21:15: cannot use i2 (variable of type int2) as int value in variable declaration Go build failed.
Это ожидается на основе результатов первой программы. Вновь определенный тип не может быть присвоен переменной int, поскольку тип i2 не int, а Вместо этого main.int2. Следовательно, нам нужно явное приведение типов, как показано ниже, и все будет работать нормально.
package main import "fmt" type int1 = int // OPTION-1 type int2 int // OPTION-2 func main() { var i1 int1 var i2 int2 // Check if integer operations works i1 += 10 i2 += 10 i1 -= 5 i2 -= 5 // check if the new type needs an explicit type conversion var i3 int = i1 var i4 int = int(i2) // NOTICE HERE !! fmt.Println(i1, i2, i3, i4) }
Вывод
5 5 5 5
2. Определение новых операций/методов
Давайте попробуем определить метод для нашего только что определенного типа.
package main import "fmt" type int1 = int // OPTION-1 type int2 int // OPTION-2 func (i int1) ToString() string { return fmt.Sprintf("%d", i) } func (i int2) ToString() string { return fmt.Sprintf("%d", i) } func main() { }
Вывод
./prog.go:8:7: cannot define new methods on non-local type int
Опять же, как и в предыдущем примере, код не запускается, и мы получаем ошибку. Но на этот раз ошибка связана с псевдонимом типа, а не с новым типом, определенным с помощью определения типа.
Поскольку сама эта операция не работает, удаляем метод func (i int1) ToString() string
и пробуем запустить оставшийся код.
package main import "fmt" type int1 = int // OPTION-1 type int2 int // OPTION-2 func (i int2) ToString() string { return fmt.Sprintf("%d", i) } func main() { var i1 int1 var i2 int2 fmt.Println(i1, i2.ToString()) }
Вывод
0 0
3. Операции назначения
Мы уже видели одну ошибку во втором примере, когда новый определенный тип не мог быть присвоен исходному базовому типу. Давайте теперь посмотрим на другую сторону.
package main import "fmt" type int1 = int // OPTION-1 type int2 int // OPTION-2 func main() { var i1 int1 var i2 int2 const ( c1 = 5 // untyped numeric const c2 int = 10 // typed numeric const ) // assign untyped constant i1 = c1 i2 = c1 // assign a typed constant i1 = c2 i2 = c2 // LINE-23 // assign a typed var var i int = 15 i1 = i i2 = i // LINE-28 fmt.Println(i1, i2) }
Вывод
./prog.go:23:7: cannot use c2 (constant 10 of type int) as int2 value in assignment ./prog.go:28:7: cannot use i (variable of type int) as int2 value in assignment Go build failed.
"источник"
Сообщения об ошибках в значительной степени говорят сами за себя.
Однако вы должны заметить, что i2 = c2
терпит неудачу, а i2 = c1
— нет. Это потому, что go выполняет строгое сопоставление типов. Таким образом, для типизированных констант (c2) или для типизированных переменных (строка 28) тип должен совпадать, тогда как для нетипизированных констант (c1) тип можно определить внутри выражения, если он совместим.
Приложения
Введите псевдоним
Его можно просто использовать для определения другого имени (псевдонима 😝), которое можно использовать вместо исходного имени. Когда бы вы это сделали?
Если вам не нравится исходное название типа, возможно, оно слишком вебозное🙈.
На самом деле для этого могут быть веские причины, см. «Материалы для чтения» в конце.
или, может быть, вы хотите рассказать миру, что вы написали этот код 🤣
package main import "fmt" type gaurav = int func main() { var leangaurav gaurav leangaurav++ fmt.Println(leangaurav) }
Определение типа
Могут быть и другие причины для использования определения типа, но одна из них — использование определения типа для поведения, подобного enum. Как этот пример из go spec, который слегка модифицирован для простоты понимания. Просмотрите спецификацию, чтобы прочитать исходный код.
type TimeZone int const ( EST TimeZone = -5 CST TimeZone = -6 MST TimeZone = -7 PST TimeZone = -8 ) func (tz TimeZone) String() string { return fmt.Sprintf("GMT%+dh", tz) }
Дополнительные материалы для чтения о псевдонимах и определениях типов
Попробуйте сами поэкспериментировать с примерами, ведь вам предстоит еще многое изучить.
Вы можете найти меня в Linkedin 👋🏻👋🏻.