В программировании компьютера ссылка — это значение, которое позволяет программе косвенно обращаться к определенным данным , таким как значение переменной или запись , в памяти компьютера или на каком-либо другом устройстве хранения . Говорят, что ссылка ссылается на данные, а доступ к данным называется разыменованием ссылки. Ссылка отличается от самих данных.
Ссылка — это абстрактный тип данных , который может быть реализован многими способами. Обычно ссылка ссылается на данные, хранящиеся в памяти данной системы, а ее внутреннее значение — это адрес памяти данных, т. е. ссылка реализуется как указатель . По этой причине часто говорят, что ссылка «указывает на» данные. Другие реализации включают смещение (разницу) между адресом данных и некоторым фиксированным «базовым» адресом, индексом или идентификатором, используемым в операции поиска в массиве или таблице , дескриптором операционной системы , физическим адресом на устройстве хранения или сетевым адресом, таким как URL .
Ссылка R — это значение, допускающее одну операцию dereference( R ), которая возвращает значение. Обычно ссылка типизирована так, что она возвращает значения определенного типа, например: [1] [2]
Ссылка на интерфейс < T > { значение T (); }
Часто ссылка также допускает операцию присваивания store( R , x ), что означает, что это абстрактная переменная . [1]
Ссылки широко используются в программировании , особенно для эффективной передачи больших или изменяемых данных в качестве аргументов процедурам или для совместного использования таких данных между различными приложениями. В частности, ссылка может указывать на переменную или запись, содержащую ссылки на другие данные. Эта идея лежит в основе косвенной адресации и многих связанных структур данных , таких как связанные списки . Ссылки повышают гибкость в том, где могут храниться объекты, как они распределяются и как они передаются между областями кода . Пока можно получить доступ к ссылке на данные, можно получить доступ к данным через нее, и сами данные не нужно перемещать. Они также упрощают совместное использование данных между различными областями кода; каждая из них сохраняет ссылку на нее.
Ссылки могут вызывать значительную сложность в программе, частично из-за возможности висячих и диких ссылок , а частично из-за того, что топология данных со ссылками представляет собой направленный граф , анализ которого может быть довольно сложным. Тем не менее, ссылки все еще проще анализировать, чем указатели, из-за отсутствия арифметики указателей .
Механизм ссылок, хотя и различается в реализации, является фундаментальной особенностью языка программирования, общей почти для всех современных языков программирования. Даже некоторые языки, которые не поддерживают прямого использования ссылок, имеют некоторое внутреннее или неявное использование. Например, соглашение о вызове по ссылке может быть реализовано как с явным, так и с неявным использованием ссылок.
Указатели являются наиболее примитивным типом ссылок. Благодаря их тесной связи с базовым оборудованием они являются одним из самых мощных и эффективных типов ссылок. Однако, также из-за этой связи, указатели требуют от программиста глубокого понимания деталей архитектуры памяти. Поскольку указатели хранят адрес ячейки памяти, а не значение напрямую, неправильное использование указателей может привести к неопределенному поведению в программе, особенно из-за висячих указателей или диких указателей . Умные указатели — это непрозрачные структуры данных , которые действуют как указатели, но к ним можно получить доступ только с помощью определенных методов.
Дескриптор — это абстрактная ссылка, которая может быть представлена различными способами. Типичным примером являются дескрипторы файлов (структура данных FILE в стандартной библиотеке ввода-вывода языка C ), используемые для абстрагирования содержимого файла. Обычно он представляет как сам файл, как при запросе блокировки файла , так и определенную позицию в содержимом файла, как при чтении файла.
В распределенных вычислениях ссылка может содержать больше, чем адрес или идентификатор; она может также включать встроенную спецификацию сетевых протоколов, используемых для поиска и доступа к указанному объекту, способ кодирования или сериализации информации. Таким образом, например, описание WSDL удаленной веб-службы можно рассматривать как форму ссылки; оно включает полную спецификацию того, как найти и привязаться к определенной веб-службе . Ссылка на живой распределенный объект является другим примером: это полная спецификация того, как построить небольшой программный компонент, называемый прокси , который впоследствии будет участвовать в одноранговом взаимодействии, и через который локальная машина может получить доступ к данным, которые реплицируются или существуют только как слабо согласованный поток сообщений. Во всех этих случаях ссылка включает полный набор инструкций или рецепт того, как получить доступ к данным; в этом смысле она служит той же цели, что и идентификатор или адрес в памяти.
Если у нас есть набор ключей K и набор объектов данных D , то любая четко определенная (однозначная) функция от K до D ∪ { null } определяет тип ссылки, где null — это образ ключа, не ссылающегося ни на что осмысленное.
Альтернативным представлением такой функции является направленный граф, называемый графом достижимости. Здесь каждый элемент данных представлен вершиной, и существует ребро от u до v , если элемент данных в u ссылается на элемент данных в v . Максимальная степень исхода равна единице. Эти графы ценны при сборке мусора , где их можно использовать для отделения доступных объектов от недоступных .
Во многих структурах данных большие, сложные объекты состоят из более мелких объектов. Эти объекты обычно хранятся одним из двух способов:
Внутреннее хранилище обычно более эффективно, поскольку существуют затраты пространства для ссылок и метаданных динамического распределения , а также затраты времени, связанные с разыменованием ссылки и выделением памяти для более мелких объектов. Внутреннее хранилище также улучшает локальность ссылок , сохраняя различные части одного и того же большого объекта близко друг к другу в памяти. Однако существует ряд ситуаций, в которых предпочтительнее внешнее хранилище:
Некоторые языки, такие как Java , Smalltalk , Python и Scheme , не поддерживают внутреннее хранилище. В этих языках все объекты единообразно доступны через ссылки.
В языке ассемблера ссылки обычно выражаются с помощью либо необработанных адресов памяти, либо индексов в таблицах. Это работает, но использовать их довольно сложно, поскольку адрес ничего не говорит о значении, на которое он указывает, даже о его размере или о том, как его интерпретировать; такая информация закодирована в логике программы. В результате в неправильных программах могут возникать неверные интерпретации, вызывающие сбивающие с толку ошибки.
Одной из самых ранних непрозрачных ссылок была ячейка cons языка Lisp , которая представляет собой просто запись, содержащую две ссылки на другие объекты Lisp, включая, возможно, другие ячейки cons. Эта простая структура чаще всего используется для построения односвязных списков , но может также использоваться для построения простых двоичных деревьев и так называемых «точечных списков», которые заканчиваются не нулевой ссылкой, а значением.
Указатель по - прежнему является одним из самых популярных типов ссылок сегодня. Он похож на ассемблерное представление необработанного адреса, за исключением того, что он несет статический тип данных , который может использоваться во время компиляции, чтобы гарантировать, что данные, на которые он ссылается, не будут неверно истолкованы. Однако, поскольку C имеет слабую систему типов , которая может быть нарушена с помощью приведения типов (явных преобразований между различными типами указателей и между типами указателей и целыми числами), неверное толкование все еще возможно, хотя и более сложно. Его преемник C++ попытался повысить безопасность типов указателей с помощью новых операторов приведения типов, ссылочного типа &
и интеллектуальных указателей в своей стандартной библиотеке , но все еще сохранил возможность обходить эти механизмы безопасности для совместимости.
Fortran не имеет явного представления ссылок, но использует их неявно в своей семантике вызова по ссылке . Ссылку Fortran лучше всего рассматривать как псевдоним другого объекта, например скалярной переменной или строки или столбца массива. Синтаксиса для разыменования ссылки или непосредственного манипулирования содержимым референта не существует. Ссылки Fortran могут быть нулевыми. Как и в других языках, эти ссылки облегчают обработку динамических структур, таких как связанные списки, очереди и деревья.
Ряд объектно-ориентированных языков, таких как Eiffel , Java , C# и Visual Basic , приняли гораздо более непрозрачный тип ссылки, обычно называемый просто ссылкой . Эти ссылки имеют типы, подобные указателям C, указывающие, как интерпретировать данные, на которые они ссылаются, но они являются типобезопасными, поскольку их нельзя интерпретировать как необработанный адрес, а небезопасные преобразования не допускаются. Ссылки широко используются для доступа к объектам и их назначения . Ссылки также используются в вызовах функций/ методов или передаче сообщений, а счетчики ссылок часто используются для выполнения сборки мусора неиспользуемых объектов.
В Standard ML , OCaml и многих других функциональных языках большинство значений являются постоянными: их нельзя изменить путем присваивания. Присваиваемые «ссылочные ячейки» предоставляют изменяемые переменные , данные, которые можно изменять. Такие ссылочные ячейки могут содержать любое значение, и поэтому им присваивается полиморфный тип α ref
, где α
следует заменить типом значения, на которое указывает. Эти изменяемые ссылки могут указывать на разные объекты в течение их жизненного цикла. Например, это позволяет строить циклические структуры данных. Ссылочная ячейка функционально эквивалентна изменяемому массиву длиной 1.
Для сохранения безопасности и эффективности реализаций ссылки не могут быть приведены к типу в ML, а также не может быть выполнена арифметика указателей. В функциональной парадигме многие структуры, которые были бы представлены с использованием указателей в языке типа C, представлены с использованием других средств, таких как мощный механизм алгебраических типов данных . Затем программист может пользоваться определенными свойствами (такими как гарантия неизменности) во время программирования, даже если компилятор часто использует машинные указатели «под капотом».
Perl поддерживает жесткие ссылки, которые функционируют аналогично ссылкам в других языках, и символические ссылки , которые являются просто строковыми значениями, содержащими имена переменных. Когда значение, которое не является жесткой ссылкой, разыменовывается, Perl считает его символической ссылкой и присваивает переменной имя, заданное значением. [3] PHP имеет похожую функцию в форме своего $$var
синтаксиса. [4]