Ответ
Go имеет статическую, строгую, номинативную систему типов с выводом типов.
Разберём по частям:
-
Статическая (Static Typing) Типы всех переменных известны и проверяются на этапе компиляции. Это позволяет отловить множество ошибок до запуска программы.
var a int = 10 // a = "hello" // Ошибка компиляции: cannot use "hello" (type string) as type int -
Строгая (Strong Typing) Go не допускает неявных преобразований между разными типами. Любое преобразование должно быть явным.
var i int = 42 var f float64 // f = i // Ошибка компиляции f = float64(i) // Правильно: явное приведение типа -
Вывод типов (Type Inference) Компилятор может автоматически определять тип переменной на основе её значения при инициализации с помощью оператора
:=.// Вместо var s string = "Go" s := "Go" // Компилятор сам выводит тип stringВажно понимать, что это не динамическая типизация. Тип переменной
sопределяется один раз и не может быть изменён. -
Номинативная для типов, структурная для интерфейсов
- Номинативная (Nominative): Два типа считаются одинаковыми, только если у них одно и то же имя и они объявлены в одном пакете.
type MyInt intсоздаёт новый, отдельный тип. - Структурная (Structural): Для интерфейсов Go использует структурную типизацию, также известную как "утиная типизация" (duck typing). Любой тип, который реализует все методы интерфейса, неявно удовлетворяет этому интерфейсу. Ему не нужно явно указывать
implements.
type Speaker interface { Speak() string } type Dog struct{} func (d Dog) Speak() string { return "Woof!" } // Dog неявно реализует Speaker type Human struct{} func (h Human) Speak() string { return "Hello!" } // Human тоже реализует Speaker - Номинативная (Nominative): Два типа считаются одинаковыми, только если у них одно и то же имя и они объявлены в одном пакете.
Ответ 18+ 🔞
Слушай, а вот Go с его системой типов — это вообще отдельная песня, пиздец. Ну, в хорошем смысле. Он как такой строгий, но справедливый дед, который тебе всё объяснит, но если накосячишь — по рукам настучит ещё на этапе компиляции, а не когда программа уже на прод улетела и накрылась медным тазом.
Короче, разбираем по косточкам, что это за зверь такой.
1. Статическая типизация (Static Typing)
Это значит, что компилятор, этот дотошный зануда, проверяет все типы ДО того, как твой код вообще запустится. Ты объявил переменную как int? Ну так и ходи с ним, блядь. Попробуй запихнуть туда строку — получишь по ебалу ошибкой компиляции. И это офигенно, потому что половина тупых косяков отсекается на берегу.
var a int = 10
// a = "hello" // Ошибка компиляции: cannot use "hello" (type string) as type int
Вот видишь? Он тебе сразу: «Не-не-не, дружок-пирожок, я тебе не PHP, тут так не прокатит».
2. Строгая типизация (Strong Typing)
А это продолжение банкета. Go — не та шлюха, которая будет делать неявные преобразования за твоей спиной. Хочешь превратить int в float64? Изволь, блядь, явно это указать. Никаких сюрпризов.
var i int = 42
var f float64
// f = i // Ошибка компиляции: "Ну ты чё, совсем, а?"
f = float64(i) // А вот так — правильно, молодец. Явно сказал, что делаешь.
3. Вывод типов (Type Inference)
А вот тут Go показывает, что он не совсем уж консервативный мудак. Он может и поумничать. Используешь короткое объявление := — и компилятор сам, как хитрая жопа, догадается, какой тип ты хочешь.
// Вместо этого занудства: var s string = "Go"
s := "Go" // Компилятор сам выводит: "Ага, тут строка. Запомнил."
Но не обольщайся! Это не динамическая типизация, ёпта. Тип s определился один раз и навсегда. Это не Python, где переменная сегодня строка, а завтра — список. Здесь порядок, блядь.
4. Номинативная для типов, но структурная для интерфейсов — вот где пиздец начинается!
- Номинативная (Nominative): Два типа — это как два паспорта. Считаются одинаковыми, только если имена совпадают и выданы в одном месте (пакете). Создал
type MyInt int— поздравляю, ты родил новый, независимый тип. Для системы это теперь не простоint, а твой личныйMyInt. Максимализм, блядь! - Структурная для интерфейсов (Structural): А вот тут — свобода, мать её! Это и есть знаменитая «утиная типизация». Если что-то ходит как утка и крякает как утка — значит, это утка. В мире Go: если твой тип имеет все методы, которые требует интерфейс, то он автоматически этот интерфейс и реализует. Никаких заявлений «я реализую такой-то интерфейс» не нужно. Просто делай свою работу.
type Speaker interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "Woof!" } // Собака не знает, что она Speaker. Но она умеет Speak(). Значит, она Speaker. Всё.
type Human struct{}
func (h Human) Speak() string { return "Hello!" } // Человек тоже. Интерфейс доволен.
Вот такая, блядь, хитрая система. С одной стороны, жёсткий контроль, чтобы не выёбывались. С другой — элегантная гибкость там, где она реально нужна. В общем, ёперный театр, но спроектированный охуенно.