con trỏ null so với mẫu đối tượng Null


27

Ghi công: Điều này phát triển từ một câu hỏi P.SE liên quan

Nền tảng của tôi là về C / C ++, nhưng tôi đã làm việc khá nhiều trong Java và hiện đang mã hóa C #. Do nền C của tôi, việc kiểm tra các con trỏ được trả lại và trả về là đã qua sử dụng, nhưng tôi thừa nhận nó thiên vị quan điểm của tôi.

Gần đây tôi đã thấy đề cập đến Mẫu đối tượng Null trong đó ý tưởng là một đối tượng luôn được trả về. Trường hợp bình thường trả về đối tượng dự kiến, dân cư và trường hợp lỗi trả về đối tượng trống thay vì con trỏ null. Tiền đề là chức năng gọi sẽ luôn có một số loại đối tượng để truy cập và do đó tránh vi phạm bộ nhớ truy cập null.

  • Vì vậy, những ưu / nhược điểm của kiểm tra null so với sử dụng Mẫu đối tượng Null là gì?

Tôi có thể thấy mã gọi sạch hơn với NOP, nhưng tôi cũng có thể thấy nơi nó sẽ tạo ra các lỗi ẩn mà không được nêu ra. Tôi thà để ứng dụng của mình thất bại nặng nề (còn gọi là một ngoại lệ) trong khi tôi đang phát triển nó hơn là có một lỗi lầm thầm lặng thoát ra ngoài tự nhiên.

  • Mẫu đối tượng Null có thể có vấn đề tương tự như không thực hiện kiểm tra null không?

Nhiều đối tượng tôi đã làm việc với các đối tượng giữ hoặc các thùng chứa của riêng họ. Có vẻ như tôi sẽ phải có một trường hợp đặc biệt để đảm bảo tất cả các container của đối tượng chính đều có các đối tượng trống của riêng họ. Có vẻ như điều này có thể trở nên xấu xí với nhiều lớp lồng.


Không phải là "trường hợp lỗi" mà là "trong mọi trường hợp là một đối tượng hợp lệ".

@ ThorbjørnRavnAndersen - điểm tốt, và tôi đã chỉnh sửa câu hỏi để phản ánh điều đó. Xin vui lòng cho tôi biết nếu tôi vẫn còn sai lệch tiền đề của NOP.

6
Câu trả lời ngắn gọn là "mẫu đối tượng null" là một cách viết sai. Nó chính xác hơn được gọi là "mô hình chống đối tượng null". Bạn thường tốt hơn với một "đối tượng lỗi" - một đối tượng hợp lệ thực hiện toàn bộ giao diện của lớp, nhưng bất kỳ việc sử dụng nào cũng gây ra cái chết lớn, đột ngột.
Jerry Coffin

1
@JerryCoffin trường hợp đó nên được chỉ định bằng một ngoại lệ. Ý tưởng là bạn không bao giờ có thể có được null và do đó không cần phải kiểm tra null.

1
Tôi không thích "mẫu" này. Nhưng có lẽ nó bắt nguồn từ các cơ sở dữ liệu quan hệ bị giới hạn quá mức, nơi dễ dàng hơn để tham khảo các "hàng null" đặc biệt trong các khóa ngoại trong quá trình sắp xếp dữ liệu có thể chỉnh sửa, trước khi cập nhật cuối cùng khi tất cả các khóa ngoại hoàn toàn không phải là null.

Câu trả lời:


24

Bạn sẽ không sử dụng Mẫu đối tượng Null ở những nơi null (hoặc đối tượng Null) được trả về vì đã xảy ra lỗi nghiêm trọng. Ở những nơi đó tôi sẽ tiếp tục trả về null. Trong một số trường hợp, nếu không có sự phục hồi, bạn cũng có thể gặp sự cố vì ít nhất bãi chứa sự cố sẽ cho biết chính xác nơi xảy ra sự cố. Trong các trường hợp như vậy khi bạn thêm xử lý lỗi của riêng mình, bạn vẫn sẽ giết quá trình (một lần nữa, tôi đã nói đối với các trường hợp không có phục hồi) nhưng việc xử lý lỗi của bạn sẽ che giấu thông tin rất quan trọng mà một bãi chứa sự cố sẽ cung cấp.

Mẫu đối tượng Null dành cho những nơi có hành vi mặc định có thể được thực hiện trong trường hợp không tìm thấy đối tượng. Ví dụ, hãy xem xét những điều sau đây:

User* pUser = GetUser( "Bob" );

if( pUser )
{
    pUser->SetAddress( "123 Fake St." );
}

Nếu bạn sử dụng NOP, bạn sẽ viết:

GetUser( "Bob" )->SetAddress( "123 Fake St." );

Lưu ý rằng hành vi của mã này là "nếu Bob tồn tại, tôi muốn cập nhật địa chỉ của anh ấy". Rõ ràng nếu ứng dụng của bạn yêu cầu Bob có mặt, bạn không muốn âm thầm thành công. Nhưng có những trường hợp loại hành vi này sẽ phù hợp. Và trong những trường hợp đó, NOP không tạo ra một mã ngắn gọn và gọn gàng hơn sao?

Ở những nơi bạn thực sự không thể sống mà không có Bob, tôi sẽ yêu cầu GetUser () ném ngoại lệ ứng dụng (nghĩa là không vi phạm truy cập hoặc bất cứ điều gì tương tự) sẽ được xử lý ở cấp cao hơn và sẽ báo cáo lỗi hoạt động chung. Trong trường hợp này, không cần NOP nhưng cũng không cần kiểm tra rõ ràng về NULL. IMO, những kiểm tra cho NULL, chỉ làm cho mã lớn hơn và mất khả năng đọc. Kiểm tra NULL vẫn là lựa chọn thiết kế phù hợp cho một số giao diện, nhưng không nhiều như một số người có xu hướng nghĩ.


4
Đồng ý với trường hợp sử dụng cho các mẫu đối tượng null. Nhưng tại sao lại trở về null khi gặp phải những thất bại thảm hại? Tại sao không ném ngoại lệ?
Apoorv Khurasia

2
@MonsterTruck: đảo ngược điều đó. Khi tôi viết mã, tôi đảm bảo xác nhận phần lớn đầu vào nhận được từ các thành phần bên ngoài. Tuy nhiên, giữa các lớp bên trong nếu tôi viết mã sao cho một hàm của một lớp sẽ không bao giờ trả về NULL, thì ở phía gọi tôi sẽ không thêm kiểm tra null chỉ để "an toàn hơn". Cách duy nhất mà giá trị đó có thể là NULL là nếu xảy ra lỗi logic thảm khốc trong ứng dụng của tôi. Trong trường hợp đó, tôi muốn chương trình của mình gặp sự cố chính xác tại vị trí đó bởi vì sau đó tôi nhận được một tệp kết xuất sự cố đẹp và đảo ngược lại trạng thái ngăn xếp và đối tượng để xác định lỗi logic.
DXM

2
@MonsterTruck: bằng cách "đảo ngược điều đó", ý tôi là, không trả lại rõ ràng NULL khi bạn xác định lỗi thảm khốc, nhưng mong đợi NULL chỉ xảy ra do một số lỗi thảm khốc không lường trước được.
DXM

Bây giờ tôi hiểu ý của bạn là gì bởi lỗi thảm khốc - một cái gì đó khiến cho việc phân bổ đối tượng tự thất bại. Đúng? Chỉnh sửa: Không thể làm @ DXM vì tên hiệu của bạn chỉ dài 3 ký tự.
Apoorv Khurasia

@MonsterTruck: kỳ lạ về điều "@". Tôi biết những người khác đã làm điều đó trước đây. Tôi tự hỏi nếu họ điều chỉnh trang web gần đây. Nó không phải được phân bổ. Nếu tôi viết một lớp và ý định của API là luôn trả về một đối tượng hợp lệ, thì tôi sẽ không yêu cầu người gọi thực hiện kiểm tra null. Nhưng lỗi thảm khốc có thể là bất cứ điều gì như lỗi lập trình viên (một lỗi đánh máy khiến NULL bị trả về), hoặc có thể một số điều kiện chủng tộc đã xóa một đối tượng trước thời điểm của nó, hoặc có thể là một số lỗi tham nhũng. Về cơ bản, bất kỳ đường dẫn mã bất ngờ nào dẫn đến NULL đều được trả về. Khi điều đó xảy ra bạn muốn ...
DXM

7

Vì vậy, những ưu / nhược điểm của kiểm tra null so với sử dụng Mẫu đối tượng Null là gì?

Ưu

  • Một kiểm tra null là tốt hơn vì nó giải quyết nhiều trường hợp. Không phải tất cả các đối tượng có một mặc định lành mạnh hoặc hành vi không op.
  • Một kiểm tra null là vững chắc hơn. Ngay cả các đối tượng có mặc định lành mạnh cũng được sử dụng ở những nơi mặc định lành mạnh không hợp lệ. Mã sẽ thất bại gần với nguyên nhân gốc nếu nó sẽ thất bại. Mã sẽ thất bại rõ ràng nếu nó sẽ thất bại.

Nhược điểm

  • Mặc định Sane thường dẫn đến mã sạch hơn.
  • Mặc định Sane thường dẫn đến các lỗi ít thảm khốc hơn nếu chúng xoay sở để đi vào tự nhiên.

"Pro" cuối cùng này là điểm khác biệt chính (theo kinh nghiệm của tôi) khi từng nên được áp dụng. "Thất bại có nên ồn ào không?". Trong một số trường hợp, bạn muốn một thất bại là khó khăn và ngay lập tức; nếu một số kịch bản không bao giờ nên xảy ra bằng cách nào đó làm. Nếu không tìm thấy tài nguyên quan trọng ... vv Trong một số trường hợp, bạn vẫn ổn với mặc định lành mạnh vì đó không thực sự là lỗi : lấy giá trị từ từ điển, nhưng ví dụ như thiếu khóa.

Giống như bất kỳ quyết định thiết kế nào khác, có những mặt thăng trầm tùy thuộc vào nhu cầu của bạn.


1
Trong phần Ưu điểm: Đồng ý với điểm đầu tiên. Điểm thứ hai là lỗi của người thiết kế vì thậm chí null có thể được sử dụng ở những nơi không nên. Không nói bất cứ điều gì xấu về mẫu chỉ phản ánh về nhà phát triển đã sử dụng mẫu không chính xác.
Apoorv Khurasia

Thất bại thảm khốc hơn là gì, không thể gửi tiền hoặc gửi (và do đó không còn) tiền mà không nhận được chúng và không biết trước khi kiểm tra rõ ràng?
user470365

Nhược điểm: Mặc định Sane có thể được sử dụng để xây dựng các đối tượng mới. Nếu một đối tượng không null được trả về, một số thuộc tính của nó có thể được sửa đổi khi tạo một đối tượng khác. Nếu một đối tượng null được trả về, nó có thể được sử dụng để tạo một đối tượng mới. Trong cả hai trường hợp, cùng một mã hoạt động. Không cần mã riêng để sửa đổi bản sao và mới. Đây là một phần của triết lý rằng mỗi dòng mã là một nơi khác cho các lỗi; giảm các dòng giảm lỗi.
Shawnhcorey

@shawnhcorey - cái gì?
Telastyn

Một đối tượng null nên có thể sử dụng như thể nó là một đối tượng thực sự. Ví dụ, hãy xem xét NaN của IEEE (không phải là số). Nếu một phương trình sai, nó được trả về. Và nó có thể được sử dụng để tính toán thêm vì mọi thao tác trên nó sẽ trả về NaN. Nó đơn giản hóa mã vì bạn không phải kiểm tra NaN sau mỗi hoạt động số học.
Shawnhcorey

6

Tôi không phải là một nguồn thông tin khách quan, nhưng chủ quan:

  • Tôi không muốn hệ thống của mình chết, bao giờ; với tôi đó là một dấu hiệu của hệ thống được thiết kế tồi hoặc không hoàn chỉnh; hệ thống hoàn chỉnh nên xử lý tất cả các trường hợp có thể và không bao giờ rơi vào trạng thái bất ngờ; để đạt được điều này tôi cần phải rõ ràng trong việc mô hình hóa tất cả các dòng chảy và tình huống; sử dụng null không phải là cách rõ ràng và nhóm rất nhiều trường hợp khác nhau dưới một umrella; Tôi thích đối tượng NonEx hiện tại là null, tôi thích NaN hơn null, ... cách tiếp cận như vậy cho phép tôi rõ ràng về những tình huống đó và xử lý chúng chi tiết như tôi muốn, trong khi null chỉ cho tôi tùy chọn null; trong môi trường như Java, bất kỳ đối tượng nào cũng có thể là null, vậy tại sao bạn muốn ẩn trong nhóm các trường hợp chung đó cũng là trường hợp cụ thể của bạn?
  • null triển khai có hành vi khác biệt lớn so với đối tượng và chủ yếu được dán vào tập hợp của tất cả các đối tượng (tại sao? tại sao? tại sao?); đối với tôi sự khác biệt lớn như vậy có vẻ như là kết quả của việc thiết kế null là dấu hiệu của lỗi trong trường hợp nào hệ thống rất có thể sẽ chết (tôi cho rằng rất nhiều người thực sự thích hệ thống của họ chết trong các bài viết trên) trừ khi được xử lý rõ ràng; với tôi đó là một cách tiếp cận thiếu sót trong gốc của nó - nó cho phép hệ thống chết theo mặc định trừ khi bạn rõ ràng quan tâm đến nó, điều đó không an toàn lắm phải không? nhưng trong mọi trường hợp, không thể viết mã xử lý giá trị null và đối tượng theo cách tương tự - chỉ một số toán tử được xây dựng cơ bản (gán, bằng, param, v.v.) sẽ hoạt động, tất cả các mã khác sẽ thất bại và bạn cần hai con đường hoàn toàn khác nhau;
  • sử dụng thang đo Null Object tốt hơn - bạn có thể đặt bao nhiêu thông tin và cấu trúc vào đó theo ý muốn; NonEx hiện tại là một ví dụ rất hay - nó có thể chứa một email của người dùng mà bạn đã cố gắng nhận và đề xuất tạo người dùng mới dựa trên thông tin đó, trong khi với giải pháp null tôi sẽ cần nghĩ cách giữ email mà mọi người đã cố gắng truy cập gần với việc xử lý kết quả null;

Trong môi trường như Java hoặc C #, nó sẽ không mang lại cho bạn lợi ích chính của thám hiểm - sự an toàn của giải pháp đã hoàn tất, vì bạn vẫn có thể nhận được null ở bất kỳ đối tượng nào trong hệ thống và Java không có phương tiện (ngoại trừ chú thích tùy chỉnh cho Đậu , v.v.) để bảo vệ bạn khỏi điều đó ngoại trừ ifs rõ ràng. Nhưng trong hệ thống không có null execaitons, tiếp cận giải pháp vấn đề theo cách như vậy (với các đối tượng đại diện cho các trường hợp đặc biệt) mang lại tất cả các lợi ích được đề cập. Vì vậy, hãy thử đọc về một thứ gì đó không phải là ngôn ngữ chính và bạn sẽ thấy mình thay đổi cách mã hóa.

Nói chung, các đối tượng / loại trả về Null / Error được coi là chiến lược xử lý lỗi rất chắc chắn và khá hợp lý về mặt toán học, trong khi chiến lược xử lý ngoại lệ của Java hoặc C chỉ giống như một bước so với chiến lược "die ASAP" - vì vậy về cơ bản để lại tất cả gánh nặng không ổn định và không thể đoán trước của hệ thống về nhà phát triển hoặc nhà bảo trì.

Cũng có những đơn vị có thể được coi là vượt trội so với chiến lược này (ban đầu cũng vượt trội về độ phức tạp của sự hiểu biết), nhưng đó là những trường hợp khi bạn cần mô hình hóa các khía cạnh bên ngoài của loại, trong khi Null Object mô hình các khía cạnh bên trong. Vì vậy, NonEx hiệnUser có thể được mô hình hóa tốt hơn dưới dạng monad may_ex hiện tại.

Và cuối cùng tôi không nghĩ rằng có bất kỳ mối liên hệ nào giữa mẫu Null Object và âm thầm xử lý các tình huống lỗi. Nó phải là cách khác - nó sẽ buộc bạn phải mô hình hóa từng trường hợp lỗi một cách rõ ràng và xử lý nó cho phù hợp. Bây giờ tất nhiên bạn có thể quyết định cẩu thả (vì lý do từng có) và bỏ qua việc xử lý trường hợp lỗi một cách rõ ràng nhưng xử lý nó một cách khái quát - đó là lựa chọn rõ ràng của bạn.


9
Lý do tôi thích ứng dụng của mình thất bại khi có điều gì đó bất ngờ xảy ra là - điều gì đó bất ngờ đã xảy ra. Chuyện đã xảy ra như thế nào? Tại sao? Tôi nhận được một bãi chứa sự cố và tôi có thể điều tra và khắc phục sự cố nguy hiểm tiềm ẩn, thay vì để nó bị ẩn trong mã. Trong C #, tất nhiên tôi có thể bắt gặp tất cả các trường hợp ngoại lệ không mong muốn để thử và khôi phục ứng dụng, nhưng ngay cả khi đó tôi muốn đăng nhập nơi xảy ra sự cố và tìm hiểu xem đó có phải là cách xử lý riêng không (ngay cả khi đó là "không ghi lại lỗi này, nó thực sự được mong đợi và có thể phục hồi ").
Luaan

3

Tôi nghĩ thật thú vị khi lưu ý rằng khả năng tồn tại của Đối tượng Null dường như hơi khác một chút tùy thuộc vào việc ngôn ngữ của bạn có được gõ tĩnh hay không. Ruby là một ngôn ngữ thực hiện một đối tượng cho Null (hoặc Niltheo thuật ngữ của ngôn ngữ).

Thay vì lấy lại một con trỏ vào bộ nhớ chưa được khởi tạo, ngôn ngữ sẽ trả về đối tượng Nil. Điều này được tạo điều kiện bởi thực tế là ngôn ngữ được gõ động. Một chức năng không được đảm bảo để luôn luôn trả về một int. Nó có thể trở lại Nilnếu đó là những gì nó cần làm. Nó trở nên phức tạp hơn và khó thực hiện điều này trong một ngôn ngữ được gõ tĩnh, bởi vì bạn tự nhiên mong đợi null có thể áp dụng cho bất kỳ đối tượng nào có thể được gọi bằng tham chiếu. Bạn sẽ phải bắt đầu triển khai các phiên bản null của bất kỳ đối tượng nào có thể là null (hoặc đi theo lộ trình Scala / Haskell và có một số loại trình bao bọc "Có thể").

MrLister đưa ra một thực tế rằng trong C ++, bạn không được đảm bảo có một tham chiếu / con trỏ khởi tạo khi bạn tạo nó lần đầu tiên. Bằng cách có một đối tượng null chuyên dụng thay vì con trỏ null thô, bạn có thể nhận được một số tính năng bổ sung thú vị. Ruby Nilbao gồm to_schức năng (toString) dẫn đến văn bản trống. Điều này thật tuyệt nếu bạn không bận tâm đến việc trả về null trên chuỗi và muốn bỏ qua việc báo cáo chuỗi mà không gặp sự cố. Các lớp mở cũng cho phép bạn ghi đè thủ công đầu ra Nilnếu cần.

Cấp điều này tất cả có thể được thực hiện với một hạt muối. Tôi tin rằng trong một ngôn ngữ động, đối tượng null có thể rất thuận tiện khi được sử dụng đúng cách. Thật không may, tận dụng tối đa nó có thể yêu cầu bạn chỉnh sửa chức năng cơ bản của nó, điều này có thể khiến chương trình của bạn khó hiểu và duy trì cho những người đã từng làm việc với các hình thức chuẩn hơn của nó.


1

Đối với một số quan điểm bổ sung, hãy xem Objective-C, trong đó thay vì có một đối tượng Null, giá trị không phải là loại hoạt động giống như một đối tượng. Bất kỳ thông điệp nào được gửi đến một đối tượng nil đều không có hiệu lực và trả về giá trị 0 / 0,0 / NO (false) / NULL / nil, bất kể loại giá trị trả về của phương thức là gì. Điều này được sử dụng như một mô hình rất phổ biến trong lập trình MacOS X và iOS và thông thường các phương thức sẽ được thiết kế sao cho một đối tượng không trả về 0 là kết quả hợp lý.

Ví dụ: nếu bạn muốn kiểm tra xem một chuỗi có một hay nhiều ký tự hay không, bạn có thể viết

aString.length > 0

và nhận được kết quả hợp lý nếu aString == nil, vì một chuỗi không tồn tại không chứa bất kỳ ký tự nào. Mọi người có xu hướng mất một thời gian để làm quen với nó, nhưng có lẽ tôi sẽ mất một thời gian để làm quen với việc kiểm tra các giá trị không ở mọi nơi trong các ngôn ngữ khác.

(Ngoài ra còn có một đối tượng đơn lẻ của lớp NSNull hoạt động khá khác biệt và không được sử dụng nhiều trong thực tế).


Objective-C làm cho điều Null Object / Null Pulum thực sự mờ. nilnhận được #defineNULL và hành xử như một đối tượng null. Đó là một tính năng thời gian chạy trong khi con trỏ null C # / Java phát ra lỗi.
Maxthon Chan

0

Đừng sử dụng nếu bạn có thể tránh nó. Sử dụng hàm xuất xưởng trả về loại tùy chọn, bộ dữ liệu hoặc loại tổng riêng. Nói cách khác, biểu thị một giá trị có khả năng mặc định bằng một loại khác với giá trị được bảo đảm không được mặc định.

Đầu tiên, hãy liệt kê desiderata sau đó suy nghĩ về cách chúng ta có thể diễn đạt điều này bằng một vài ngôn ngữ (C ++, OCaml, Python)

  1. bắt sử dụng không mong muốn của một đối tượng mặc định tại thời gian biên dịch.
  2. làm rõ liệu một giá trị đã cho có khả năng được mặc định hay không trong khi đọc mã.
  3. chọn giá trị mặc định hợp lý của chúng tôi, nếu có, một lần cho mỗi loại . Chắc chắn không chọn một mặc định có khả năng khác nhau ở mỗi trang web cuộc gọi .
  4. làm cho nó dễ dàng cho các công cụ phân tích tĩnh hoặc một con người grepđể săn lùng các lỗi tiềm ẩn.
  5. Đối với một số ứng dụng , chương trình sẽ tiếp tục bình thường nếu bất ngờ được cung cấp một giá trị mặc định. Đối với các ứng dụng khác , chương trình sẽ tạm dừng ngay lập tức nếu được cung cấp một giá trị mặc định, lý tưởng nhất là theo cách thông tin.

Tôi nghĩ rằng sự căng thẳng giữa Mẫu đối tượng Null và các con trỏ null xuất phát từ (5). Tuy nhiên, nếu chúng ta có thể phát hiện lỗi đủ sớm, (5) sẽ trở thành lỗi.

Hãy xem xét ngôn ngữ này bằng ngôn ngữ:

C ++

Theo tôi, một lớp C ++ thường có thể được xây dựng mặc định vì nó giúp giảm bớt sự tương tác với các thư viện và giúp sử dụng lớp này trong các thùng chứa dễ dàng hơn. Nó cũng đơn giản hóa sự kế thừa vì bạn không cần phải nghĩ về việc xây dựng siêu lớp nào để gọi.

Tuy nhiên, điều này có nghĩa là bạn không thể biết chắc giá trị của loại MyClasscó ở "trạng thái mặc định" hay không. Bên cạnh việc đưa vào một trường bool nonemptyhoặc tương tự với trạng thái mặc định bề mặt khi chạy, điều tốt nhất bạn có thể làm là tạo ra các phiên bản mới MyClasstheo cách bắt buộc người dùng kiểm tra nó .

Tôi khuyên bạn nên sử dụng một chức năng nhà máy mà trả về một std::optional<MyClass>, std::pair<bool, MyClass>hoặc một tài liệu tham khảo r-giá trị vào std::unique_ptr<MyClass>nếu có thể.

Nếu bạn muốn chức năng xuất xưởng của mình trả về một số trạng thái "giữ chỗ" khác với trạng thái được tạo mặc định MyClass, hãy sử dụng std::pairvà đảm bảo rằng tài liệu của bạn thực hiện điều này.

Nếu chức năng của nhà máy có một tên duy nhất, thật dễ dàng để grepđặt tên và tìm kiếm sự chậm chạp. Tuy nhiên, thật khó grepcho các trường hợp mà lập trình viên nên sử dụng chức năng của nhà máy nhưng không được .

Tháng 10

Nếu bạn đang sử dụng một ngôn ngữ như OCaml, thì bạn chỉ có thể sử dụng một optionloại (trong thư viện tiêu chuẩn OCaml) hoặc một eitherloại (không phải trong thư viện tiêu chuẩn, nhưng dễ dàng tự cuộn). Hoặc một defaultableloại (tôi đang tạo thành thuật ngữ defaultable).

type 'a option =
    | None
    | Some of 'a

type ('a, 'b) either =
    | Left of 'a
    | Right of 'b

type 'a defaultable =
    | Default of 'a
    | Real of 'a

Một defaultablenhư trình bày ở trên là tốt hơn so với một cặp vì người sử dụng bắt buộc đối sánh mẫu để trích xuất các 'avà có thể không chỉ đơn giản là bỏ qua các yếu tố đầu tiên của cặp.

Tương đương với defaultableloại như được hiển thị ở trên có thể được sử dụng trong C ++ bằng cách sử dụng một std::variantvới hai phiên bản cùng loại, nhưng các phần của std::variantAPI không sử dụng được nếu cả hai loại đều giống nhau. Ngoài ra, đó là một cách sử dụng kỳ lạ std::variantvì các hàm tạo kiểu của nó không được đặt tên.

Con trăn

Bạn không nhận được bất kỳ kiểm tra thời gian biên dịch nào cho Python. Nhưng, được gõ động, thường không có trường hợp nào bạn cần một thể hiện giữ chỗ của một số loại để xoa dịu trình biên dịch.

Tôi khuyên bạn chỉ nên ném một ngoại lệ khi bạn buộc phải tạo một thể hiện mặc định.

Nếu điều đó không được chấp nhận, tôi khuyên bạn nên tạo một DefaultedMyClasskế thừa từ MyClassvà trả lại từ chức năng xuất xưởng của bạn. Điều đó mua cho bạn sự linh hoạt về chức năng "khai thác" trong các trường hợp mặc định nếu bạn cần.

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.