Всем привет! Cегодня делимся заключительной частью перевода статьи «Что есть и чего нет в Go». Напоминаем, в первой части речь шла о элементах, которые есть в Go, сегодня же поговорим о том, чего в Go нет.
Перевод данного материала подготовлен в преддверии старта нового потока по курсу «Разработчик Golang».
Go создавался с оглядкой назад, и его базовая комплектация действительно хорошо составлена: у него есть сборка мусора, пакеты, функции первого класса, лексическая область видимости, интерфейс системных вызовов и неизменяемые строки, текст которых обычно кодируется в UTF-8. Но он имеет сравнительно мало фич и вряд ли будет увеличивать их количество. Например, у него нет неявных числовых преобразований, нет конструкторов или деструкторов, нет перегрузки операторов, нет значений параметров по умолчанию, нет наследования, нет дженериков, нет исключений, нет макросов, нет аннотаций функций и нет локального хранилища потока.
Элементы, которых нет в Go
Неявное преобразование чисел
В программировании преобразование типов подразумевает смену типа данных объекта на другой. Неявное преобразование означает, что это изменение производится автоматически интерпретатором или компилятором. Например, присвоение int-значения переменной, которой ранее было присвоено значение с плавающей запятой. Такое преобразование недоступно в Go. Когда тип не упоминается при объявлении переменной, ему присваивается подходящий тип, например, int, float, string и т. д. на основе синтаксической композиции литерала. В приведенном ниже примере Go выдаст ошибку, поскольку он найдет два разных типа данных и не сможет с ними работать. Это происходит, поскольку компилятор Go неявно преобразует int
в float64
.
a := 1.0 // same as float64(1.0)
b := 1 // same as int(1)
fmt.Printf("%f", a*b)
// invalid operation: a * b (mismatched types float64 and int)
Конструкторы и деструкторы
Задача конструкторов заключается в первичной обработке и инициализации объекта, а деструктора — в уничтожении объект по истечении срока его службы и освобождении памяти. В отличие от других объектно-ориентированных парадигм, в Go нет классов. Следовательно, и концепции конструкторов и деструкторов тоже не существует.
Перегрузка операторов
Перегрузка операторов — это способ, с помощью которого операторы могут выполнять операции, определенные пользователями. Операторы ведут себя в соответствии с переданными аргументами. Например, в C ++ +
оператор может использоваться для объединения строк, а также сложения двух целых чисел. Значение «+» также может быть определено пользователем и изменено в соответствии с потребностями программы. В JavaScript операция типа '1' + 1
приведет к выводу строки "11"
из-за более высокого приоритета строк. Такие определения недопустимы в Go, операторы работают строго и выполняют операции только с определенными типами данных аргументов.
Значения по умолчанию
Go не допускает значения по умолчанию в прототипах функций или при перегрузке функций. Спецификация языка Go необыкновенно мала и специально поддерживается таковой для упрощения синтаксического анализа. В отличие от других языков, где вы можете передавать значения по умолчанию/необязательные параметры в функцию, в Go вы можете только проверить, было ли передано значение. Другой подход к значениям по умолчанию в Go будет примерно таким.
func Concat1(a string, b int) string {
if a == "" {
a = "default-a"
}
if b == 0 {
b = 5
}
return fmt.Sprintf("%s%d", a, b)
}
Наследование
Поскольку Go не следует привычной иерархии классов объектно-ориентированного программирования, структуры в Go не наследуются друг от друга. В целом, наследование — это процедура на языках ООП, в которой один класс наследует свойства и метод класса своих родителей. Наследование может углубляться на несколько уровней. Однако в Go структура может быть составлена просто путем предоставления указателя или встраивания в сотрудничающие структуры. Пример композиции на Go приведен ниже. Заменой классов могут быть интерфейсы в Go. Интерфейсы существуют и в других языках, однако интерфейсы Go удовлетворяются неявно.
type TokenType uint16
type Token struct {
Type TokenType
Data string
}
type IntegerConstant struct {
Token *Token
Value uint64
}
Обобщенное программирование
Обобщенное программирование — это форма, в которой мы подключаем шаблоны, известные как дженерики, которые на самом деле не являются истинным исходным кодом, но компилируются компилятором для преобразования их в исходный код. Давайте попробуем понять шаблоны простым способом. Думайте о шаблонах в программировании как о форме. Мы создаем форму, в которой важные детали шаблона оставлены пустыми и должны быть заполнены позже во время компиляции. Затем, когда нам нужно создать что-то из этого шаблона, мы просто указываем детали, например, тип.
template<typename T>
class MyContainer
{
// Container that deals with an arbitrary type T
};
void main()
{
// Make MyContainer take just ints.
MyContainer<int> intContainer;
}
Приведенный выше фрагмент написан на C ++. Шаблону не предоставляется тип, но он предоставляется при инициализации MyContainer. Мы также можем указать другие типы, такие как float
, double
и т. д. в соответствии с нашими потребностями. Обобщенные шаблоны, полезны при запуске алгоритмов над множеством данных, имеющих несколько типов.
Исключения
Исключение указывает на целесообразное условие, которое приложение могло бы хотеть перехватить. Через исключения мы можем разрешать ситуации, при которых программа может не работать. Проверенное исключение не приводит к полной остановке выполнения, оно может быть перехвачено и обработано. Go не имеет исключений, он имеет только ошибки как интерфейсы и встроенные ошибки. Ключевое отличие ошибок от исключений состоит в том, что они указывают на серьезную проблему и должны решаться немедленно, поэтому программирование на Go становится более строгим. Ошибки в Go необходимо проверять в явном виде по мере их возникновения.
Макросы
Макросы представляют собой макрокоманды. Это способ минимизации повторяющихся задач в программировании путем определения предварительно заданного выхода для данного набора входов. Например, если мы хотим получить квадрат числа в C, мы можем просто написать x * x
, где x
— переменная, но мы также можем определить макрос, который возвращает квадрат числа каждый раз, когда он нам нужен. Макросы не являются функциями. Макросы недоступны в Go.
#define square(x) ((x) * (x))
int main() {
int four = square(2); // same as 2 * 2
return 0;
}
Аннотации функций
Аннотации — это способ связать метаданные с параметрами функции. В Python аннотации синтаксически поддерживаются и являются полностью опциональными. Давайте рассмотрим небольшой пример, чтобы описать аннотации в Python.
def foo(a: int, b: 'description', c: float) -> float: print(a+b+c)
foo(1, 3, 2) // prints 6.0
foo('Hello ', , 'World!') // prints Hello World!
В приведенном выше коде параметры a
, b
и c
аннотированы некоторыми метаданными. a
и c
аннотируются типами int
и float
, тогда как b
предоставляется со строковым описанием. foo
напечатает определенный вывод, несмотря на тип аргументов, упомянутых в аннотациях.
Локальное хранилище потока
Локальное хранилище потока — это метод компьютерного программирования, который использует статическую или глобальную память, локализованную для потока. Это статическая область, где данные копируются для каждого потока в программе. Когда несколько потоков используют одни и те же статические данные для одной и той же задачи, они могут скопировать их из локального хранилища потока, а не хранить их самостоятельно.
Заключение
Разработка Go была сосредоточена на простоте и элегантности. У него быстрый, маленький и простой синтаксис. В отличие от других языков ООП, в нем меньше концепций, которые должны отложиться в голове. Создатели Go выбрали простоту языка, не добавляя мультипликативную сложность к смежным частям языка. Следовательно, Go не имеет фич, которые делают парсер медленнее и больше. Простота — ключ к хорошему программному обеспечению.
ПРИМЕЧАНИЕ. Фрагменты кода в этой статье скопированы из различных статей в Интернете.
На этом все.
Автор: MaxRokatansky