Некоторые языки, включая 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. Это потому, что, как только вы сделаете копию ссылки, они теперь независимы. Хотя они могут ссылаться на одну и ту же переменную, при манипулировании ссылкой она изменит то, на что она ссылается, а не на значение ссылки.
Последний пример демонстрирует поведение при изменении назначения одного из указателей для указания на новый адрес. Из-за ограничений ссылок это единственная доступная операция.
Оставайтесь с нами … В следующем посте будет представлено другое свойство, доступное только указателям, указатель указателя.
Для получения дополнительной информации об указателях я нашел следующие ресурсы полезными