Привет! Я Го, и я ненавижу, когда меня называют Голангом. Я функциональный, императивный, параллельный и объектно-ориентированный язык программирования. В этой статье я расскажу вам, как я реализую классические объектно-ориентированные конструкции, такие как структуры и методы.
Структура
Структура — это совокупный тип данных, который я предоставляю программистам, чтобы они могли группировать вместе ноль или более именованных значений произвольного типа в виде единой сущности. Ниже приведены некоторые из способов, которыми я разрешаю объявлять структуры.
type Point struct { X int Y int } // or type Point struct {X, Y int}
И для создания переменной или указателя указанного выше типа структуры синтаксис выглядит следующим образом.
var point Point // Declares a varible of type Point var pointp *Point // Declares a pointer of type Point
Как для переменных, так и для указателей я разрешаю доступ к полю с использованием записи через точку.
point.X = 4 pointp.X = 4
Последнее утверждение эквивалентно
(*pointp).X = 4
Я разрешаю инициализацию структуры одним из двух способов. Вы можете либо указать значение для каждого поля в правильном порядке, либо перечислить некоторые или все имена полей и соответствующие им значения в любом порядке.
p := Point{1, 2}// X and Y get assigned 1 and 2 respectively // or p := Point{Y: 1}// Y gets assigned 1 and X is assigned its nil value
Есть кое-что в структурах, которые я разрешаю, а именно сравнение структур. Но это возможно, только если все поля структуры сопоставимы.
p := Point{1, 2} q := Point{1, 2} r := Point{X:2, Y:3} p == q // true q == r // false p == r // false
Что касается наследования, то я его не разрешаю, но то, что я разрешаю вместо этого, называется встраиванием структуры . Несмотря на то, что это может выглядеть и ощущаться как наследование, между ними есть существенная разница, которая станет очевидной при обсуждении интерфейсов. Позвольте мне объяснить встраивание, приведя пример.
type Circle struct { Point Radius int } var c Circle c.X = 0 c.Y = 0 c.Radius = 5
Итак, встраивая, я разрешаю доступ к полям структуры Point внутри структуры Circle. Но я не разрешаю этого при инициализации структур.
c := Circle{X: 0, Y: 0, Radius: 5} // compile error c := Circle{Point{X:0, Y:0}, 5} // compiles successfully
Методы
Я разрешаю объявление метода так же, как объявление функции с дополнительным параметром перед именем функции. Параметр связывает функцию с типом этого параметра. Напишем метод и прикрепим его к объектам типа Point.
func (p Point) Distance (q Point) { return math.Hypot(q.X - p.X, q.Y - p.Y) }
Дополнительный параметр p называется получателем метода. Я не использую специальное имя, такое как этот или я, для получателя. Я разрешаю выбирать имена получателей так же, как и любой другой параметр. Получатель также может быть указателем на переменную.
func (p *Point) ScaleBy (factor float64) { p.X *= factor p.Y *= factor }
Для меня nil является допустимым получателем, если его значение nil имеет смысл. Как и в случае связанного списка целых чисел, где значение nil означает пустой список.
// An IntList is a linked list of integers. // A nil *IntList represents an empty list. type IntList struct { Value int Tail *IntList } //Sum returns the sum of the list elements. func (list *IntList) Sum() { if list == nil { return 0 } return list.Value + list.Tail.Sum() }
Я надеюсь, что все, что мы обсудили до сих пор, имеет смысл и побудит вас писать код на Go. В следующей серии статей об интерфейсах, горутинах, каналах и параллелизме будет больше информации.