В следующей статье будут представлены главные особенности программирования на языке Go, а также указано чем именно от отличается от Java.
Содержание статьи
- Встроенные типы Go
- Указатели и ссылки в Go
- Объектно-ориентированное программирование в Java и Go
- Функциональное программирование в Go
- Конкурентность в Go
- Отсутстующие в Go инструменты программирования
- Комплексные числа в Go
Следующий код Java адаптирован из книги Effective Java и имплементирует класс, представляющий сложное число.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public final class Complex { private final double re; private final double im; public Complex(double re, double im) { if (Double.isNaN(re) || Double.isNaN(im)) { throw new ArithmeticException(); } this.re = re; this.im = im; } public double realPart() { return re; } public double imaginaryPart() { return im; } public Complex add(Complex c) { return new Complex(re + c.re, im + c.im); } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Complex)) return false; Complex c = (Complex) o; return Double.compare(re, c.re) == 0 && Double.compare(im, c.im) == 0; } @Override public int hashCode() { int result = 17 + Double.hashCode(re); result = 31 * result + Double.hashCode(im); return result; } @Override public String toString() { return "(" + re + (im < 0 ? "" : "+") + im + "i)"; } public static void main(String[] args) { Complex z = new Complex(1, 2); System.out.println(z.add(z)); } } |
Та же программа, написанная на Go, будет состоять из двух отдельных пакетов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package complex import ( "fmt" "math" ) type Complex struct { re, im float64 } func New(re, im float64) Complex { if math.IsNaN(re) || math.IsNaN(im) { panic("NaN") } return Complex{re, im} } func (c Complex) Real() float64 { return c.re } func (c Complex) Imag() float64 { return c.im } func (c Complex) Add(d Complex) Complex { return New(c.re+d.re, c.im+d.im) } func (c Complex) String() string { if c.im < 0 { return fmt.Sprintf("(%g%gi)", c.re, c.im) } return fmt.Sprintf("(%g+%gi)", c.re, c.im) } |
1 2 3 4 5 6 7 8 9 10 11 |
package main import ( "complex" "fmt" ) func main() { z := complex.New(1, 2) fmt.Println(z.Add(z)) } |
Обратите внимание, что в данном случае Golang использует значения структуры, а Java использует отсылки на объекты. Также опущены методы равенства и hashCode
, так как Go уже определяет равенство для структур через сравнение.
Встроенные типы в Go
В Go строки предоставляются языком; строка ведет себя как срез байтов, но является неизменной. Хеш-таблицы предоставляются языком. Они называются картами (map).
Указатели и ссылки в Go
В Go есть указатели на значения всех типов, не только объекты и массивы. Для любого типа T есть соответствующий указатель типа *T — он указывает на значения типа Т.
Массивы в Go являются значения. Когда массив используется как параметр функции, функция получает копию массива, а не указатель на него. Однако на практике функции часто использует срезы для параметров; срезы являются ссылками на базовые массивы.
Определенные типы (карты, срезы и каналы) передаются через ссылки, а не через значение. Это значит, что передача карты к функции не копирует карту; если функция изменяет карту, изменению будет видно вызывающему. Говоря терминами Java, можно думать об этом как о ссылки на карту.
Обработка ошибок в Go
Вместо исключений Go использует ошибки для указания важности таких событий, как конец файла и вызов паники при истечении времени для ошибок вроде попытки индексирования массива за его границами.
Объектно-ориентированное программирование в Java и Go
В Go нет классов с конструкторами. Вместо экземпляра методов, иерархии наследия классов и динамического метода, Go предоставляет структуры и интерфейсы.
Go разрешает создание методов любого типа; упаковка не требуется. Получатель метода, что соответствует этому в Java, может быть прямым значением или указателем.
Go предоставляет два уровня доступа по аналогии с публичным и пакетно-приватно в Java. Декларации верхнего уровня являются публичными, если их названия начинаются с заглавной буквы, в противном случае они пакетно-приватными.
Подробнее: Объектно-ориентированное программирование в Go без наследования.
Функциональное программирование в Go
В Go функции являются категорией первого класса. Значения функции можно использовать и передавать как и другие значения, а литералы функции могут ссылаться на переменные, определенные в закрывающейся функции.
Подробнее: Функциональное программирование в Go.
Конкурентность в Go
Отдельные потоки выполнения, горутины и каналы связи между ними, каналы, предоставляются самим языком программирования.
Подробнее: Конкурентное программирование в Go [руководство].
Отсутстующие в Go инструменты программирования
Go не поддерживает неявную конвертацию типов. Операции, которые смешивают разные типы, требуют явного преобразования. Вместо этого Go предлагает нетипизированные числовые константы без ограничений.
Go не поддерживает перегрузку функций. Функции и методы в одной области должны иметь уникальные названия. Ради альтернативы можете ознакомиться с темой Необязательные параметры и перегрузка методов.
В Go есть несколько встроенных типов данных генериков, таких как срезы и карты, и универсальных функций вроде добавления и копирование. Тем не менее, там нет механизма для написания ваших собственных универсальных функций генериков. Подробнее: Генерики (альтернативы и обходные пути).
Комплексные числа в Go
В Go есть встроенная поддержка для комплексных чисел.
1 2 |
z := 1+2i fmt.Println(z + z) |
Эту особенность языка используют очень редко.