Начнем кодить!!

Посмотрите на код ниже и подумайте, что он напечатает. [%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 — новый тип.

Какая разница ?

Нам нужно посмотреть на это со следующих точек зрения:

  1. Поведение операций относительно нового типа

Мы хотим проверить, ведут ли новые типы точно так же, как исходный тип 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)
}

Дополнительные материалы для чтения о псевдонимах и определениях типов

  1. https://go.dev/talks/2016/refactor.article

Попробуйте сами поэкспериментировать с примерами, ведь вам предстоит еще многое изучить.

Вы можете найти меня в Linkedin 👋🏻👋🏻.