Некоторые языки, включая C, C ++, поддерживают указатели. Другие языки, включая C ++, Java, Python, Ruby, Perl и PHP, поддерживают ссылки. На первый взгляд и ссылки, и указатели очень похожи, обе используются для того, чтобы одна переменная обеспечивала доступ к другой. Поскольку оба предоставляют множество одинаковых возможностей, часто неясно, чем отличаются эти разные механизмы. В этой статье я проиллюстрирую разницу между указателями и ссылками.
Почему это важно
Указатели лежат в основе эффективного го. Большинство программистов изучают Go на одном из языков, упомянутых выше. Следовательно, понимание различий между указателями и ссылками имеет решающее значение для понимания Go. Даже если вы исходите из языка, который использует указатели, реализация указателей в Go отличается от C и C ++ в том, что она сохраняет некоторые из приятных свойств ссылок, сохраняя при этом силу указателей.
Остальная часть этой статьи написана с намерением широко рассказать о концепции ссылок, а не о конкретной реализации. Мы будем использовать Go в качестве эталонной реализации для указателей.
В чем разница?
Указатель — это переменная, в которой хранится адрес другой переменной.
Ссылка — это переменная, которая ссылается на другую переменную.
Чтобы проиллюстрировать нашу точку зрения, используйте следующий пример на C ++, который поддерживает как указатели, так и ссылки.
int i = 3; int *ptr = &i; int &ref = i;
Первая строка просто определяет переменную. Второй определяет указатель на адрес памяти этой переменной. Третий определяет ссылку на первую переменную.
Мало того, что операторы разные, но вы также используете по-разному. С указателями необходимо использовать оператор * для разыменования. Со ссылкой оператор не требуется. Понятно, что вы собираетесь работать с указанной переменной.
Продолжая наш пример, обе следующие строки изменят значение i на 13.
*ptr = 13; ref = 13;
Вы можете спросить, что произойдет, если я попытаюсь получить прямой доступ к ptr без предварительной разыменования. Это подводит нас ко второму критическому различию между указателями и ссылками. Указатели могут быть переназначены, а ссылки — нет. Другими словами, указатель может быть назначен другому адресу.
Рассмотрим следующий пример в Go:
package main
import "fmt"
var ap *int
func main() {
a := 1 // define int
b := 2 // define int
ap = &a
// set ap to address of a (&a)
// ap address: 0x2101f1018
// ap value : 1
*ap = 3
// change the value at address &a to 3
// ap address: 0x2101f1018
// ap value : 3
a = 4
// change the value of a to 4
// ap address: 0x2101f1018
// ap value : 4
ap = &b
// set ap to the address of b (&b)
// ap address: 0x2101f1020
// ap value : 2
}
До сих пор вы могли делать все вышеперечисленное в достаточно сходной манере, используя ссылки, и часто с более простым синтаксисом.
Оставайтесь со мной, следующий пример проиллюстрирует, почему указатели являются более мощными, чем ссылки.
Расширение функции выше:
...
ap2 := ap
// set ap2 to the address in ap
// ap address: 0x2101f1020
// ap value : 2
// ap2 address: 0x2101f1020
// ap2 value : 2
*ap = 5
// change the value at the address &b to 5
// ap address: 0x2101f1020
// ap value : 5
// ap2 address: 0x2101f1020
// ap2 value : 5
// If this was a reference ap & ap2 would now
// have different values
ap = &a
// change ap to address of a (&a)
// ap address: 0x2101f1018
// ap value : 4
// ap2 address: 0x2101f1020
// ap2 value : 5
// Since we've changed the address of ap, it now
// has a different value then ap2
}
Вы можете поэкспериментировать и поиграть сами на ходу play: http://play.golang.org/p/XJtdLxFoeO
Ключ к пониманию разницы во втором примере.
Если бы мы работали со ссылками, мы бы не смогли изменить значение b на * ap и отразить это в * ap2. Это потому, что, как только вы сделаете копию ссылки, они теперь независимы. Хотя они могут ссылаться на одну и ту же переменную, при манипулировании ссылкой она изменит то, на что она ссылается, а не на значение ссылки.
Последний пример демонстрирует поведение при изменении назначения одного из указателей для указания на новый адрес. Из-за ограничений ссылок это единственная доступная операция.
Оставайтесь с нами … В следующем посте будет представлено другое свойство, доступное только указателям, указатель указателя.
Для получения дополнительной информации об указателях я нашел следующие ресурсы полезными