Какой смысл иметь указатели в Go? - PullRequest
79 голосов
/ 08 декабря 2009

Я знаю, что указатели в Go допускают мутацию аргументов функции, но было бы проще, если бы они использовали только ссылки (с соответствующими const или изменяемыми квалификаторами). Теперь у нас есть указатели и для некоторых встроенных типов, таких как карты и каналы, неявный переход по ссылке.

Я что-то упустил или указатели в Go - просто ненужное осложнение?

Ответы [ 4 ]

37 голосов
/ 06 мая 2013

Мне очень нравится пример, взятый из http://www.golang -book.com / 8

func zero(x int) {
    x = 0
}
func main() {
    x := 5
    zero(x)
    fmt.Println(x) // x is still 5
}

в отличие от

func zero(xPtr *int) {
    *xPtr = 0
}
func main() {
    x := 5
    zero(&x)
    fmt.Println(x) // x is 0
}
32 голосов
/ 08 декабря 2009

Ссылки не могут быть переназначены, в то время как указатели могут. Одно это делает указатели полезными во многих ситуациях, когда ссылки не могут быть использованы.

31 голосов
/ 25 марта 2014

Указатели полезны по нескольким причинам. Указатели позволяют контролировать структуру памяти (влияет на эффективность кэша процессора). В Go мы можем определить структуру, в которой все члены находятся в смежной памяти:

type Point struct {
  x, y int
}

type LineSegment struct {
  source, destination Point
}

В этом случае структуры Point внедряются в структуру LineSegment. Но вы не можете всегда встраивать данные напрямую. Если вы хотите поддерживать такие структуры, как двоичные деревья или связанный список, то вам нужно поддерживать некоторый указатель.

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode
}

Java, Python и т. Д. Не имеют этой проблемы, поскольку не позволяют встраивать составные типы, поэтому нет необходимости синтаксически различать встраивание и указание.

Проблемы со структурами Swift / C #, решаемые с помощью указателей Go

Возможная альтернатива для достижения того же - провести различие между struct и class, как это делают C # и Swift. Но это имеет ограничения. Хотя обычно вы можете указать, что функция принимает структуру в качестве параметра inout, чтобы избежать копирования структуры, она не позволяет хранить ссылки (указатели) на структуры. Это означает, что вы никогда не сможете рассматривать структуру как ссылочный тип, когда вы найдете это полезным, например, создать распределитель пула (см. ниже).

Пользовательский распределитель памяти

Используя указатели, вы также можете создать свой собственный распределитель пула (это очень упрощено с удалением множества проверок, чтобы просто показать принцип):

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode

  nextFreeNode *TreeNode; // For memory allocation
}

var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0] 

func poolAlloc() *TreeNode {
    node := firstFreeNode
    firstFreeNode  = firstFreeNode.nextFreeNode
    return node
}

func freeNode(node *TreeNode) {
    node.nextFreeNode = firstFreeNode
    firstFreeNode = node
}

Обмен двух значений

Указатели также позволяют реализовать swap. Это меняет значения двух переменных:

func swap(a *int, b *int) {
   temp := *a
   *a = *b
   *b = temp
}

Заключение

Java никогда не была в состоянии полностью заменить C ++ для системного программирования в таких местах, как Google, отчасти потому, что производительность не может быть настроена в одинаковой степени из-за отсутствия возможности контролировать структуру и использование памяти (ошибки в кеше влияют на производительность) значительно). Go стремится заменить C ++ во многих областях и поэтому должен поддерживать указатели.

27 голосов
/ 08 декабря 2009

Go разработан, чтобы быть кратким, минималистским языком. Поэтому все началось с простых значений и указателей. Позже, по необходимости, были добавлены некоторые ссылочные типы (срезы, карты и каналы).


Язык программирования Go: часто задаваемые вопросы по проектированию языка: почему карты, фрагменты и ссылки на каналы используются, а массивы являются значениями?

"В этой теме много истории. Вначале карты и каналы были синтаксически указателями, и было невозможно объявить или использовать экземпляр без указателя. Кроме того, мы боролись с тем, как должны работать массивы. В конце концов мы решили, что строгое разделение указателей и значений усложнило использование языка. Введение справочных типов, в том числе срезов для обработки ссылочной формы массивов, решило эти проблемы. Справочные типы добавляют некоторую прискорбную сложность языку, но они оказывают большое влияние на удобство использования: Язык Go стал более продуктивным и удобным, когда они были представлены. "


Быстрая компиляция - главная цель разработки языка программирования Go; это имеет свои затраты. Кажется, что одной из жертв является возможность помечать переменные (за исключением основных констант времени компиляции) и параметры как неизменяемые. Это было запрошено, но отклонено.


golang-nuts: иди на язык. Некоторые отзывы и сомнения.

"Добавление const к системе типов заставляет его появляться везде, и вынуждает убрать его везде, если что-то меняется. Пока там может быть некоторая выгода для маркировки объектов неизменными, мы не думаю, квалификатор константного типа - это путь. "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...