Por que o novo índice de operador de chapéu do recurso de corte de matriz C # 8 começa em 0?

156

O C # 8.0 apresenta uma maneira conveniente de dividir matrizes - consulte o post oficial do blog em C # 8.0 .

A sintaxe para acessar o último elemento de uma matriz é

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

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

Gostaria de saber por que a indexação para acessar os elementos para trás começa em 1 em vez de 0? Existe uma razão técnica para isso?

Michael Pittino
fonte
11
Observe que os intervalos C ++ também são [beginInclusive, endExclusive). É uma convenção comum.
bommelding 8/01/19
3
@ Sinin: Com base nesse post do blog, a sintaxe para retornar tudo seria value[0..^0], uma vez que o índice final é exclusivo (que é como a maioria dos outros idiomas também funciona). Além disso, convenientemente, value[^i..^0]você fornecerá os últimos iitens.
BlueRaja - Danny Pflughoeft
1
@bommelding: C ++ rbegin()discorda um pouco dessa noção - o primeiro item desse intervalo não é o único além do fim. ;-)
DevSolar 9/01/19
1
Oh legal, esta parece ser o equivalente a indexação negativo em python:value[-1] # 13
cs95
1
@ Coldspeed E em Ruby o mesmo que Python. Suponho que ambos tenham emprestado esta convenção de Perl.
Wayne Conrad

Respostas:

170

Resposta oficial

Para uma melhor visibilidade, aqui está um comentário de Mads Torgersen explicando essa decisão de design na postagem do blog C # 8 :

Decidimos seguir o Python quando se trata da aritmética do começo e do fim. 0 designa o primeiro elemento (como sempre) e  ^0 o elemento “length'th”, ou seja, aquele logo no final. Dessa forma, você obtém um relacionamento simples, em que a posição de um elemento desde o início mais a posição do final é igual ao comprimento. o  x in  ^x é o que você teria subtraído do comprimento se tivesse feito as contas sozinho.

Por que não usar o operador menos ( -) em vez do ^operador new hat ( )? Isso tem a ver principalmente com intervalos. Novamente, de acordo com o Python e a maior parte do setor, queremos que nossos intervalos sejam inclusivos no início, exclusivos no final. Qual é o índice que você passa para dizer que um intervalo deve percorrer todo o caminho até o fim? Em C #, a resposta é simples: x..^0vai do  x final. No Python, não há um índice explícito que você possa fornecer: -0não funciona, porque é igual ao 0primeiro elemento! Assim, em Python, você tem que deixar o índice final off completamente para expressar um intervalo que vai para o fim: x... Se o final do intervalo for calculado, você precisará se lembrar de ter uma lógica especial caso isso ocorra 0. Como em x..-yondeyfoi computado e saiu para 0. Este é um incômodo comum e fonte de bugs.

Por fim, observe que índices e intervalos são tipos de primeira classe no .NET / C #. O comportamento deles não está vinculado ao que eles são aplicados ou mesmo para serem usados ​​em um indexador. Você pode definir totalmente seu próprio indexador que usa Index e outro que usa Range- e vamos adicionar esses indexadores a, por exemplo  Span. Mas você também pode ter métodos que levam intervalos, por exemplo.

Minha resposta

Acho que isso corresponde à sintaxe clássica à qual estamos acostumados:

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

Se usasse 0, seria confuso quando as duas sintaxes fossem usadas lado a lado. Dessa forma, possui menor carga cognitiva.

Outras linguagens como Python também usam a mesma convenção.

Martin Zikmund
fonte
13
Correção menor ao comentário de Mads: você não precisa deixar o índice final completamente em python. Você pode usar Noneno lugar de um número: [0,1,2,3,4][2:None] == [2,3,4]. Mas, sim, você não pode usar um número inteiro como índice final (sem calcular obviamente o comprimento).
Giacomo Alzetta
4
Espere ... o que há de errado x..? Parece bom e nunca tive problemas com a [3:]sintaxe do python .
precisa saber é o seguinte
8
@ mowwwalker - isso já não está coberto na cotação? "Então, em Python ... Se o final do intervalo for calculado, você precisará se lembrar de ter uma lógica especial caso chegue a 0"
Damien_The_Unbeliever
3
O comentário de @mowwwalker Mads foi sobre casos em que você não sabe qual será o valor do índice porque é calculado de alguma forma. Eles estão dizendo que, no caso de você querer calcular endIndexcomo um índice negativo (isto é, índice do final), você terá uma descontinuidade entre números negativos e positivos, porque 0nesse caso não funcionará da maneira correta. Como indiquei, você deve substituir 0por Noneisso. Isso significa que seu código deve se parecer com, seq[startIndex:endIndex or None]por exemplo. O or Nonedeve ser omitido se endIndexse espera que seja positivo.
Giacomo Alzetta
5
É bom ver que eles não estão repetindo o erro do Python com a coisa -0. Lidar com esse caso especial é um grande aborrecimento e é fácil demais esquecer.
user2357112 suporta Monica