Mục đích của việc sử dụng NIL để đại diện cho các nút null là gì?


17

Trong khóa học Thuật toán và Cấu trúc dữ liệu của tôi, các giáo sư, trang trình bày và cuốn sách ( Giới thiệu về thuật toán, ấn bản thứ 3 ) đã sử dụng từ này NILđể biểu thị ví dụ một đứa trẻ của một nút (trong cây) không tồn tại.

Một lần, trong một bài giảng, thay vì nói NIL, bạn cùng lớp của tôi đã nói null, và giáo sư đã sửa lỗi cho anh ấy, và tôi không hiểu tại sao các giáo sư nhấn mạnh từ này.

Có một lý do tại sao mọi người sử dụng từ NILthay vì null, hoặc none, hoặc bất kỳ từ nào khác? Có NILmột số ý nghĩa đặc biệt mà những người khác không có? Có một số lý do lịch sử?

Lưu ý rằng tôi cũng đã thấy một vài nơi trên web, ví dụ, từ nullnày được sử dụng thay vì NIL, nhưng thường thì từ cuối cùng này được sử dụng.

Câu trả lời:


25

Theo như tôi đang quan tâm, null, nil, nonenothingđược tên chung cho khái niệm tương tự: một giá trị đại diện cho “sự vắng mặt của một giá trị”, và đó là hiện diện trong nhiều loại khác nhau (gọi tắt là các loại nullable ). Giá trị này thường được sử dụng khi giá trị thường xuất hiện, nhưng có thể bị bỏ qua, ví dụ như một tham số tùy chọn. Các ngôn ngữ lập trình khác nhau thực hiện điều này khác nhau và một số ngôn ngữ có thể không có bất kỳ khái niệm nào như vậy. Trong các ngôn ngữ có con trỏ, đó là một con trỏ null . Trong nhiều ngôn ngữ hướng đối tượng, null không phải là một đối tượng: gọi bất kỳ phương thức nào trên đó là một lỗi. Để đưa ra một vài ví dụ:

  • Trong Lisp, nilthường được sử dụng để đại diện cho sự vắng mặt của một giá trị. Không giống như hầu hết các ngôn ngữ khác, nilcó cấu trúc - đó là một biểu tượng có tên "NIL". Đây cũng là danh sách trống (vì danh sách phải là ô khuyết điểm, nhưng đôi khi không có ô khuyết điểm vì danh sách trống). Cho dù nó được thực hiện bởi một con trỏ null dưới mui xe, hoặc như một biểu tượng như bất kỳ con trỏ nào khác, đều phụ thuộc vào việc triển khai.
  • Trong Pascal, nillà một giá trị con trỏ (hợp lệ trong bất kỳ loại con trỏ nào) có thể không được hủy đăng ký.
  • Trong C và C ++, bất kỳ loại con trỏ nào cũng bao gồm một NULLgiá trị khác với bất kỳ con trỏ nào đến một đối tượng hợp lệ.
  • Trong Smalltalk, nillà một đối tượng không có phương thức xác định.
  • Trong Java và trong C #, nulllà một giá trị của bất kỳ loại đối tượng nào. Bất kỳ nỗ lực truy cập vào một lĩnh vực hoặc phương pháp nullkích hoạt một ngoại lệ.
  • Trong Perl, undefkhác với bất kỳ giá trị vô hướng nào khác và được sử dụng trong toàn bộ ngôn ngữ và thư viện để biểu thị sự vắng mặt của giá trị Real thực tế.
  • Trong Python, Nonekhác với bất kỳ giá trị nào khác và được sử dụng trong toàn bộ ngôn ngữ và thư viện để biểu thị sự vắng mặt của giá trị Real real.
  • Trong ML (SML, OCaml), Nonelà một giá trị của bất kỳ loại nào trong sơ đồ loại 'a option, có chứa NoneSome xcho bất kỳ xloại nào 'a.
  • Trong Haskell, khái niệm tương tự sử dụng tên NothingJust xcho các giá trị và Maybe acho loại.

Trong các bài thuyết trình thuật toán, tên nào được sử dụng có xu hướng xuất phát từ nền tảng của người trình bày hoặc ngôn ngữ được sử dụng trong các ví dụ mã.

Trong các bài thuyết trình ngữ nghĩa, các tên khác nhau có thể được sử dụng để chỉ ví dụ: NULLđịnh danh biểu thị hằng số con trỏ trong ngôn ngữ và giá trị trong ngữ nghĩa. Tôi không nghĩ có bất kỳ sơ đồ đặt tên tiêu chuẩn nào và một số bài thuyết trình cho thấy sự khác biệt về phông chữ hoặc hoàn toàn không đi vào cú pháp cụ thể.nTôitôi

Có thể là giảng viên của bạn muốn sử dụng từ nullcho hằng số con trỏ null trong ngôn ngữ lập trình được sử dụng trong khóa học (Java hoặc C #?) Và NILđể biểu thị sự vắng mặt của một nút trong một số cấu trúc dữ liệu, có thể được thực hiện hoặc không được thực hiện như một hằng con trỏ null (ví dụ, như đã thấy ở trên, trong Lisp, NILthường không được triển khai như một con trỏ null). Sự khác biệt này sẽ có liên quan khi thảo luận về các kỹ thuật triển khai cho các cấu trúc dữ liệu. Khi thảo luận về chính các cấu trúc dữ liệu, khái niệm hằng-con trỏ null là không liên quan, chỉ có khái niệm không bằng với bất kỳ giá trị nào khác.

Không có sơ đồ đặt tên tiêu chuẩn. Một giảng viên hoặc sách giáo khoa khác có thể sử dụng các tên khác nhau.


Hai ví dụ nữa. Mục tiêu C có cả NULL(cho khả năng tương thích C) và nil; gọi phương thức trên nillà không có. JavaScript có cả null(một giá trị không đại diện cho gì) và undefined(giá trị thậm chí không được đặt).
200_success

1
"Trong các ngôn ngữ hướng đối tượng, null không phải là một đối tượng: gọi bất kỳ phương thức nào trên đó là một lỗi." - Điều này không đúng với tất cả các ngôn ngữ, bao gồm một số ngôn ngữ bạn đã liệt kê. Trong Ruby và Smalltalk, nillà một đối tượng giống như bất kỳ đối tượng nào khác, đó là một ví dụ NilClass, không có khái niệm nào khác về "null-ness", và đặc biệt, không có con trỏ null. Trong Scala, Nilrất khác biệt so với null, nullgiống như một con trỏ rỗng, tuy nhiên, nó thực sự có một kiểu ( Null), Nillà một đối tượng cũ thông thường, ví dụ đơn lẻ của EmptyListlớp nếu bạn muốn, và cũng có
Jörg W Mittag

1
... Nothingđó là loại đáy và không có ví dụ, và Unitđó là loại thường trình mà không trả về giá trị và có dụ singleton (). nullbằng cách nào đó mang theo khái niệm "con trỏ null" hoặc "tham chiếu null", không phải vì đó là bằng cách nào đó vốn có trong thuật ngữ mà đơn giản là vì sự phổ biến của các ngôn ngữ như C, C ++, D, Java, C #, sử dụng nó trong điều này cách thức. NILkhông mang ý nghĩa này, mặc dù nó thực sự được sử dụng theo cách đó, ví dụ như trong Pascal, Modula-2 và Oberon. Trong Ruby, nilcó nhiều phương pháp hữu ích: nil.to_i # => 0, nil.to_s # => '', ...
Jörg W Mittag

1
... nil.to_a # => [], nil.to_h # => {}, nil.to_f # => 0.0, nil.inspect # => 'nil', và vân vân. Bạn có thể xem danh sách đầy đủ ở đây .
Jörg W Mittag

3

Tôi tin rằng lý do cho việc sử dụng cả nilnull là vì trước đây chủ yếu là một danh từ và sau này chủ yếu là một tính từ (tôi đã kiểm tra trên web và trong từ điển giấy của tôi: American Heritage 1992).

Về ý nghĩa và lịch sử, NIL là một sự co lại từ "nihil" trong tiếng Latin có nghĩa là "không có gì".

Theo hiểu biết của tôi, việc sử dụng tên nilđể biểu thị một con trỏ null được giới thiệu với ngôn ngữ lập trình Lisp (1958).

Một con trỏ null là một giá trị con trỏ được cho là không trỏ đến, và do đó không nên bị hủy đăng ký. Trong hầu hết các trường hợp, con trỏ chỉ đơn giản là địa chỉ bộ nhớ. Bất kỳ biến nào (nghĩa là bất kỳ vị trí nào) được dự định chứa một con trỏ như vậy sẽ luôn chứa một số cấu hình của các bit và bất kỳ cấu hình nào như vậy có thể được đọc dưới dạng địa chỉ bộ nhớ. Do đó, thông thường giá trị nilsẽ là địa chỉ của vùng nhớ bị cấm đối với chương trình, do đó gây ra một số dạng lỗi (có thể bị gián đoạn) nếu chương trình cố gắng hủy đăng ký nil, chỉ có thể là lỗi.

Có một giá trị tiêu chuẩn được xác định trước duy nhất để đóng vai trò này là điều cần thiết trong các ngôn ngữ sử dụng con trỏ một cách rõ ràng, vì điều quan trọng là có thể kiểm tra xem một con trỏ có đang chỉ vào một vị trí bộ nhớ hay không. Thông thường, trong Lisp, một danh sách được xây dựng như một chuỗi các "khuyết điểm" chứa con trỏ "xe hơi" đến một thành phần danh sách và con trỏ "cdr" cho cặp tiếp theo. Trong cặp cuối cùng của danh sách, con trỏ thứ hai là nil.

Điều này tương ứng với định nghĩa đệ quy của danh sách là danh sách trống hoặc thành phần danh sách được nối với danh sách. Do đó một danh sách không có yếu tố được đại diện bởi nil. Danh sách trống này xảy ra là danh tính của danh sách đơn.

Vì danh sách có thể được sử dụng để biểu diễn các tập hợp, nên tập hợp trống có thể được đại diện bởi nil.

Do đó, nilvề mặt lịch sử là một giá trị con trỏ đặc biệt, nhưng được hiểu là một giá trị nhận dạng đặc biệt cho các miền trừu tượng khác, chẳng hạn như danh sách hoặc bộ.

Một con trỏ bằng nillà một con trỏ null, null là một tính từ chứ không phải là một từ thực chất (tức là một danh từ).

Việc sử dụng phối hợp cả hai từ, như tính từ và danh từ khá phù hợp với thực tiễn khác. Null vòng loại thường được sử dụng cho số không của cấu trúc đại số, chẳng hạn như danh tính của một đơn chất: phần tử null . Danh sách tạo thành một monoid , trong đó giá trị nil là danh tính. Điều tương tự cũng đúng với các tập hợp (mặc dù chúng tạo thành một đại số với nhiều thuộc tính hơn). Người ta nói tương tự rằng một số nguyên là null khi nó bằng không.

Có rất nhiều biến thể về việc sử dụng những từ này một từ khác, chẳng hạn như không, tùy thuộc vào tác giả và đặc điểm riêng của ngôn ngữ lập trình.

Hai ý nghĩa chính là , như đã giải thích ở trên

  • như một "giá trị không xác định" tiêu chuẩn, thực sự đại diện cho sự vắng mặt của bất kỳ giá trị có thể sử dụng nào.

  • làm giá trị nhận dạng của một số miền

Điều này cho thấy không hoàn toàn chính xác khi khẳng định rằng NIL là " một giá trị đại diện cho sự vắng mặt của một giá trị ", như được thực hiện bởi Gilles trong câu trả lời được chấp nhận . Nó phụ thuộc vào ngôn ngữ và cách sử dụng. Các lập trình LISP ngôn ngữ có thể giới thiệu NIL trong thuật ngữ lập trình 55 năm về trước. Trong LISP, NILlà danh sách trống và có thể được ghi chú tương ứng (), đó là đại diện tự nhiên của danh sách trống.Nó không đại diện cho sự vắng mặt của một giá trị. Đôi khi, nó được sử dụng làm trình giữ chỗ cho các giá trị bị thiếu, mặc dù điều đó thường được tránh chính xác vì danh sách trống là một giá trị. Những gì đại diện cho một giá trị còn thiếu trong một cấu trúc trong bất kỳ đối tượng tùy ý, được chọn bởi lập trình viên, không thể nhầm lẫn với các giá trị chấp nhận được.

Hai khái niệm khá khác nhau, mặc dù chúng tôi đã chỉ ra ở trên rằng chúng có thể liên quan với nhau. Thật thú vị khi có một chế độ phân loại chi tiết về việc sử dụng thuật ngữ được liệt kê bởi Gilles'answer, để xem liệu cách sử dụng của mỗi từ này được định hướng nhiều hơn theo nghĩa này hay nghĩa khác.

Tên không nhiều hơn những gì chúng được gán có nghĩa trong một bối cảnh nhất định, bởi bất cứ ai đang xác định diễn ngôn. Một số cách sử dụng phổ biến hơn, tự nhiên hơn hoặc nhất quán hơn, nhưng người ta phải luôn kiểm tra các định nghĩa và đảm bảo ý nghĩa nào được dự định trong mỗi bối cảnh. Và người ta không nên luôn luôn mong đợi thuật ngữ đã được lựa chọn với hương vị hoặc tính nhất quán.


0

NIL là một đối tượng có giá trị cho người lập trình biết đối tượng không hợp lệ. Nó đặc biệt hữu ích trong C ++ trong đó NULL được định nghĩa là 0. Nếu bạn hủy tham chiếu NULL trong C ++, bạn sẽ nhận được hành vi không xác định. Nếu bạn hủy tham chiếu NIL (một con trỏ tới một đối tượng trống mà bạn đã xác định), bạn sẽ nhận được một đối tượng mà bạn có thể biết nằm ngoài phần cuối của cấu trúc dữ liệu của bạn. Thật tuyệt vời để ngăn chặn các lỗi chương trình thảm khốc và phát hiện lỗi.

Bạn có thể sử dụng NIL trong các trường hợp như danh sách được liên kết đôi, vì nó là đầu và cuối của danh sách để theo dõi cả đầu và đuôi, và đảm bảo rằng -> tiếp theo và -> con trỏ trước không bao giờ hủy tham chiếu NULL.


Theo như tôi có thể thấy, điều này chỉ đơn giản là không chính xác. Không có "NIL" trong C ++ .
David Richerby

1
Tôi nghĩ rằng bạn giải thích sai câu trả lời của tôi. Liên kết bạn cung cấp không có mối tương quan với câu trả lời của tôi. Tôi đã đề xuất rằng nil là một đối tượng do người dùng định nghĩa, được xác định trên cơ sở mỗi lớp, để trỏ đến một đối tượng trống (nhưng hợp lệ) của lớp đó.
xóa bỏ

Cách bạn viết "NIL một đối tượng" (nhấn mạnh của tôi) chứ không phải là "NIL có thể được định nghĩa là một đối tượng" làm cho nó giống như bạn đang mô tả một tính năng ngôn ngữ, thay vì một phong cách lập trình. Tuy nhiên, nếu câu trả lời của bạn hoàn toàn là về phong cách lập trình, thì nó không thực sự thuộc chủ đề ở đây.
David Richerby
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.