Tại sao chỉ số toán tử mũ mới từ tính năng cắt mảng C # 8 bắt đầu từ 0?


156

C # 8.0 giới thiệu một cách thuận tiện để cắt các mảng - xem blogpost chính thức của C # 8.0 .

Cú pháp để truy cập phần tử cuối cùng của một mảng là

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

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

Tôi đang tự hỏi tại sao việc lập chỉ mục để truy cập các phần tử ngược lại bắt đầu từ 1 thay vì 0? Có một lý do kỹ thuật cho việc này?


11
Lưu ý rằng phạm vi C ++ cũng được [beginInclusive, endExclusive). Đó là một quy ước chung.
bommelding

3
@Sinatr: Dựa trên bài đăng trên blog đó, cú pháp trả về mọi thứ sẽ là value[0..^0], vì chỉ mục kết thúc là độc quyền (đó là cách mà hầu hết các ngôn ngữ khác cũng hoạt động). Ngoài ra, thuận tiện, value[^i..^0]sẽ cung cấp cho bạn các imục cuối cùng .
BlueRaja - Daniel Pflughoeft

1
@bommelding: C ++ rbegin()phần nào không đồng ý với khái niệm đó - mục đầu tiên trong phạm vi đó cũng không phải là mục đích cuối cùng. ;-)
DevSolar

1
value[-1] # 13
Thật

1
@coldspeed Và trong Ruby giống như Python. Tôi đoán cả hai đều mượn quy ước này từ Perl.
Wayne Conrad

Câu trả lời:


170

Câu trả lời chính thức

Để nhìn rõ hơn, đây là một bình luận từ Mads Torgersen giải thích quyết định thiết kế này từ bài đăng trên blog của C # 8 :

Chúng tôi quyết định theo dõi Python khi nói đến số học từ đầu đến cuối. 0 chỉ định phần tử đầu tiên (như mọi khi) và  ^0 phần tử chiều dài của trò chơi, tức là phần tử bên phải. Bằng cách đó, bạn có được một mối quan hệ đơn giản, trong đó vị trí của một yếu tố từ đầu cộng với vị trí của nó từ đầu bằng với độ dài. các  x trong  ^x là những gì bạn sẽ trừ vào chiều dài nếu bạn muốn thực hiện phép tính cho mình.

Tại sao không sử dụng toán tử dấu trừ ( -) thay cho ^toán tử hat ( ) mới? Điều này chủ yếu phải làm với phạm vi. Một lần nữa phù hợp với Python và hầu hết các ngành công nghiệp, chúng tôi muốn các phạm vi của chúng tôi được bao gồm ngay từ đầu, độc quyền ở cuối. Chỉ số bạn vượt qua để nói rằng một phạm vi sẽ đi đến cuối cùng là gì? Trong C #, câu trả lời rất đơn giản: x..^0đi từ  x cuối đến cuối. Trong Python, không có chỉ mục rõ ràng nào bạn có thể đưa ra: -0không hoạt động, bởi vì nó bằng 0, phần tử đầu tiên! Vì vậy, trong Python, bạn phải loại bỏ hoàn toàn chỉ mục kết thúc để thể hiện một phạm vi đi đến cuối : x... Nếu kết thúc của phạm vi được tính toán, thì bạn cần nhớ phải có logic đặc biệt trong trường hợp nó xuất hiện 0. Như trong x..-y, ở đâuyđã được tính toán và đi ra 0. Đây là một phiền toái phổ biến và nguồn gốc của lỗi.

Cuối cùng, lưu ý rằng các chỉ mục và phạm vi là các loại lớp đầu tiên trong .NET / C #. Hành vi của họ không gắn liền với những gì họ được áp dụng, hoặc thậm chí được sử dụng trong một bộ chỉ mục. Bạn hoàn toàn có thể xác định người lập chỉ mục của riêng bạn để lấy Index và một người lập chỉ mục khác Range- và chúng tôi sẽ thêm các chỉ mục như vậy vào ví dụ  Span. Nhưng bạn cũng có thể có các phương thức lấy phạm vi, ví dụ.

Câu trả lời của tôi

Tôi nghĩ rằng điều này là để phù hợp với cú pháp cổ điển mà chúng ta đã sử dụng để:

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

Nếu nó được sử dụng 0, sẽ gây nhầm lẫn khi hai cú pháp được sử dụng song song. Bằng cách này, nó có tải nhận thức thấp hơn .

Các ngôn ngữ khác như Python cũng sử dụng quy ước tương tự.


13
Sửa lỗi nhỏ cho bình luận của Mads: bạn không cần phải bỏ hoàn toàn chỉ số kết thúc bằng python. Bạn có thể sử dụng Nonethay cho một số : [0,1,2,3,4][2:None] == [2,3,4]. Nhưng, vâng, bạn không thể sử dụng một số nguyên làm chỉ số kết thúc (mà không tính toán độ dài rõ ràng).
Giacomo Alzetta

4
Đợi đã .. có chuyện gì với x..? Điều đó có vẻ ổn và tôi chưa bao giờ gặp vấn đề với [3:]cú pháp python .
mowwwalker

8
@mowwwalker - không phải đã được nêu trong trích dẫn? "Vì vậy, trong Python ... Nếu kết thúc phạm vi được tính toán, thì bạn cần phải nhớ có logic đặc biệt trong trường hợp nó xuất hiện về 0"
Damien_The_Unbeliever

3
@mowwwalker Nhận xét của Mads là về các trường hợp mà bạn không biết giá trị chỉ mục sẽ là gì vì nó được tính theo một cách nào đó. Họ đang nói rằng trong trường hợp bạn muốn tính endIndexlà một chỉ số âm (tức là chỉ số từ cuối), bạn sẽ có sự gián đoạn giữa các số âm và số dương vì 0sẽ không hoạt động đúng cách trong trường hợp đó. Như tôi đã chỉ ra bạn phải thay thế 0bằng cách Noneđó. Điều này có nghĩa là mã của bạn sẽ trông giống như seq[startIndex:endIndex or None]ví dụ. Các or Nonenên được bỏ qua nếu endIndexđược dự kiến sẽ được tích cực.
Giacomo Alzetta

5
Thật tốt khi thấy họ không lặp lại sai lầm của Python với điều -0. Xử lý trường hợp đặc biệt đó là một rắc rối lớn và quá dễ để quên.
user2357112 hỗ trợ Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.