Чому новий індекс-оператор капелюха з функції нарізки масивів C № 8 не починається з 0?


156

C # 8.0 пропонує зручний спосіб нарізати масиви - див. Офіційний допис для C # 8.0 .

Синтаксис доступу до останнього елемента масиву є

int value[] = { 10, 11, 12, 13 };

int a = value[^1]; // 13
int b = value[^2]; // 12

Мені цікаво, чому індексація доступу до елементів назад починається з 1 замість 0? Чи є для цього технічна причина?


11
Зауважте, що діапазони C ++ також є [beginInclusive, endExclusive). Це загальна конвенція.
бомбардування

3
@Sinatr: Виходячи з цього повідомлення в блозі, синтаксис для повернення все був би value[0..^0], оскільки індекс закінчення є ексклюзивним (саме так працює і більшість інших мов). Також зручно value[^i..^0]подарує вам останні iпредмети.
BlueRaja - Danny Pflughoeft

1
@bommelding: C ++ rbegin()дещо не погоджується з цим поняттям - перший пункт із цього діапазону теж не є безперервним . ;-)
DevSolar

1
О, круто, це виглядає як еквівалент негативного індексування в python:value[-1] # 13
cs95

1
@coldspeed І в Ruby те саме, що і Python. Я здогадуюсь, вони обидва позичили цю конвенцію у Perl.
Уейн Конрад

Відповіді:


170

Офіційна відповідь

Для кращої наочності, ось коментар Мадса Торгерсена, який пояснює це дизайнерське рішення з блогу C # 8 :

Ми вирішили наслідувати Python, коли мова йде про арифметику від початку і від кінця. 0 позначає перший елемент (як завжди) та  ^0 елемент "довжина", тобто праворуч від кінця. Таким чином ви отримуєте просте співвідношення, де положення елемента від початку плюс його положення від кінця дорівнює довжині. x в  ^x то , що ви б відняти від довжини , якби ви зробили обчислити число самостійно.

Чому б не використовувати мінус ( -) замість нового ^оператора hat ( )? В першу чергу це стосується діапазонів. Знову у відповідність з Python та більшою частиною галузі, ми хочемо, щоб наші асортименти були включені на початку, ексклюзивні в кінці. Який індекс ви передаєте, щоб сказати, що діапазон повинен пройти до кінця? У C # відповідь проста: x..^0йде від  x кінця. У Python немає явного індексу, який ви можете дати: -0не працює, тому що він дорівнює 0першому елементу! Таким чином , в Python, ви повинні залишити кінцевий індекс від повністю виразити діапазон , який йде до кінця: x... Якщо обчислюється кінець діапазону, то вам потрібно пам’ятати, що у вас є спеціальна логіка на випадок 0. Як у x..-y, деyбув обчислений і вийшов до 0. Це звичайна неприємність і джерело помилок.

Нарешті, зауважте, що індекси та діапазони - це першокласні типи в .NET / C #. Їх поведінка не пов'язана з тим, до чого вони застосовуються, або навіть використовуються в індексаторі. Ви можете повністю визначити свій власний індексатор, який приймає індекс, і інший, який бере Range- і ми збираємося додати такі індексатори, наприклад  Span. Але ви також можете мати методи, наприклад, діапазони.

Моя відповідь

Я думаю, що це відповідає класичному синтаксису, до якого ми звикли:

value[^1] == value[value.Length - 1]

Якщо він використовував 0, це було б заплутано, коли два синтаксиси використовувались поруч. Таким чином він має меншу пізнавальну навантаження.

Інші мови, такі як Python, також використовують цю ж умову.


13
Незначні виправлення до коментарів Мадса: вам не доведеться повністю залишати кінцевий індекс у python. Ви можете використовувати Noneзамість ряду: [0,1,2,3,4][2:None] == [2,3,4]. Але, так, ви не можете використовувати ціле число як кінцевий індекс (очевидно, не обчислюючи довжину).
Джакомо Альзетта

4
Зачекайте .. що з цим x..? Це здається прекрасним, і у мене ніколи не було проблем із [3:]синтаксисом python .
mowwwalker

8
@mowwwalker - чи не про це вже йдеться у цитаті? "Так у Python ... Якщо обчислюється кінець діапазону, вам потрібно пам’ятати, щоб мати особливу логіку, якщо вийде 0"
Damien_The_Unbeliever

3
@mowwwalker Mads коментар стосувався випадків, коли ви не знаєте, яким буде значення індексу, оскільки воно обчислюється якимось чином. Вони говорять, що у випадку, якщо ви хочете обчислити endIndexяк від'ємний індекс (тобто індекс від кінця), у вас виникне розрив між від'ємними та позитивними числами, оскільки 0в цьому випадку не буде працювати належним чином. Як я зазначив, що вам потрібно замінити 0на Noneдля цього. Це означає, що ваш код повинен виглядати, seq[startIndex:endIndex or None]наприклад. or NoneПовинна бути опущена , якщо , endIndexяк очікується, буде позитивним.
Джакомо Альзетта

5
Добре бачити, що вони не повторюють помилку Python із річчю -0. Поводження з цим особливим випадком - це величезні клопоти та їх занадто легко забути.
user2357112 підтримує Моніку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.