Programming Taskbook 0
Download 1.62 Mb. Pdf ko'rish
|
Abramyan-Pascal2016-1
- Bu sahifa navigatsiya:
- [1, 2, 3] Writeln(b); // [5, 2, 3]
Глава 5. Дополнительные средства обработки массивов 95 переменной. Поскольку в нашем примере a и b описаны в разных операто- рах описания, для них были сгенерированы разные внутренние типы (условно говоря, arr1_10_integer1 и arr1_10_integer2), которые не считаются эквивалентными и, в частности, не являются совместимыми по присваи- ванию. Поэтому компилятор фактически сообщает, что он не может преоб- разовать тип arr1_10_integer1 к arr1_10_integer2, но поскольку эти имена яв- ляются внутренними и отсутствуют в программе, он заменяет их на текст исходных описаний (чем, возможно, только сбивает с толку неопытного программиста). Указанная особенность, связанная с эквивалентностью типов, приво- дит к аналогичным проблемам при использовании статических массивов в качестве параметров подпрограмм (или возвращаемых значений функций). Поскольку мы в дальнейшем не собираемся работать со статическими мас- сивами, мы не будем обсуждать детали этих проблем (см. по этому поводу [2, п. 13.7.1]). Упомянутые особенности и связанные с ними проблемы яв- ляются добавочным аргументом в пользу того, чтобы отказаться от ис- пользования статических массивов в программах на языке PascalABC.NET. С динамическими массивами ситуация совершенно иная. Для эквива- лентности динамических массивов (и, следовательно, их совместимости по присваиванию) достаточно, чтобы они имели одинаковый тип элементов. Где и как они описаны в программе, не имеет никакого значения. Подоб- ная эквивалентность называется структурной (в отличие от именной экви- валентности статических массивов). Заметим, что структурная эквивалент- ность в PascalABC.NET реализована также для множеств set of T [1, гл. 3] и процедурных типов (см. п. 1.3). Поскольку размер динамического массива при описании не указыва- ется, он не влияет на совместимость массивов. Но при таком подходе по- элементное копирование при присваивании теряет смысл. И действитель- но, присваивание динамических массивов означает совсем другое: оно лишь изменяет ссылку, хранящуюся в изменяемой переменной-массиве. Приведем пример: var a := Arr(1, 2, 3); var b := Arr(6, 7); b := a; Поскольку в генераторах Arr для переменных a и b использованы па- раметры одинакового типа (integer), эти переменные имеют одинаковый тип array of integer и поэтому совместимы по присваиванию. Подчеркнем, что с ними связываются массивы разного размера. Фактически в a хранит- ся ссылка на массив с элементами 1, 2, 3, а в b хранится ссылка на массив с элементами 6 и 7. Присваивание вида b := a изменяет лишь ссылку, храня- щуюся в переменной b. Это приводит к важным последствиям. Во-первых, 96 программа теряет связь с массивом, содержащим элементы 6, 7, поскольку эта связь обеспечивалась только за счет ссылки, хранящейся в b. Массив становится недоступным программе и в дальнейшем автоматически удаля- ется из памяти специальной подсистемой платформы .NET — сборщиком мусора (garbage collector) [3, п. 8.1.2]. Во-вторых, доступ к массиву с эле- ментами 1, 2, 3 теперь оказывается возможным и с помощью переменной а, и с помощью переменной b. Дополним предыдущий фрагмент следующими операторами b[0] := 5; Write(a); // [5, 2, 3] Мы видим, что изменение элемента b[0] привело к тому, что одновре- менно изменился и массив a (так как фактически у нас имеется единствен- ный массив с двумя именами). Указанное обстоятельство необходимо учитывать при передаче дина- мических массивов в качестве параметров подпрограмм. В частности, сле- дует понимать, что и передача динамического массива по значению, и пе- редача его по ссылке (с указанием модификатора var) будет, во-первых, выполняться одинаково быстро (так как передача по значению не будет приводить к поэлементному копированию) и, во-вторых, позволит изме- нять элементы переданного массива (даже при передаче массива по значе- нию, поскольку созданная в подпрограмме при такой передаче копия ссыл- ки будет обращаться к тому же самому массиву). Как при подобном способе присваивания создать настоящую копию массива, которую в дальнейшем можно было бы обрабатывать независи- мо? Для этого в PascalABC.NET предусмотрено несколько способов. Простейшим является использование функции Copy(a) с единствен- ным параметром — копируемым массивом. Эта функция создает и воз- вращает копию данного массива (точнее, возвращается ссылка на создан- ную в памяти копию). Пример: var a := Arr(1, 2, 3); var b := Arr(6, 7); b := Copy(a); b[0] := 5; Writeln(a); // [1, 2, 3] Writeln(b); // [5, 2, 3] Мы видим, что теперь изменение значения элемента массива b никак не повлияло на содержимое массива a. Заметим, что для получения копий массива или его частей можно ис- пользовать срезы (см. п. 3.7), поскольку любой срез фактически является копией некоторой части массива. Например, в предыдущем фрагменте мы |
Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling
ma'muriyatiga murojaat qiling