Зрiзи - це об'єкти типу T[]
для будь-якого заданого типу Т
. Зріз
надає доступ до підмножини масиву значень Т
, або просто вказує на
весь масив. Зрiзи та динамічні масиви - це одне і те ж.
Зріз складається з двох елементів - вказівник на початковий елемент та довжину зрізу:
T* ptr;
// беззнакове 32-бiтне число на 32-бiтних платформах
// чи беззнакове 64-бiтне число на 64-бiтних платформах.
size_t length;
При створенні нового динамічного масиву, для зрiзу відразу видiляється частина пам'ятi:
auto arr = new int[5];
assert(arr.length == 5); // пам'ять, на яку посилається arr.ptr
Фактична виділена пам'ять у цьому випадку повністю керується збирачем сміття (GC або garbage collector). Повернутий зріз буде вказувати на існуючі елементи.
За допомогою оператора зрізу можна також отримати зріз, який вказує
на деякий вже існуючий блок пам'яті. Оператор зрізу може бути
застосований до інших зрізів, статичних масивів, структур/класів, у
яких було реалізовано метод opSlice
і так далі.
У цьому виразі origin[початок .. кінець]
оператор зрізу використовується
для отримання зрізу всіх елементів origin
від початок
до елементу
перед кінець
:
auto newArr = arr[1 .. 4]; // iндекс 4 не врахований
assert(newArr.length == 3);
newArr[0] = 10; // змiнює newArr[0], який співпадає з arr[1]
Такі зрізи генерують новий доступ до існуючої пам'яті. Вони не створюють нову копію. Якщо жоден зрiз більше не містить посилання на пам'ять, або на її частину - вона буде очищена збирачем сміття.
Зрізи надають можливість писати дуже ефективний код. Наприклад, парсери зазвичай працюють з одним блоком пам'яті, просто посилаючись на неї за допомогою зрiзiв, без необхідності виділяти нових блоків пам'яті.
Як було зазначено у попередньому розділі, вираз [$]
є скороченою формою для arr.length
. Отже, arr[$]
буде посилатись на елемент, який
знаходиться за останнім елементом зрізу, таким чином буде згенеровано
RangeError
(якщо не була відключена перевiрка меж зрiзiв).