Tập quán của Null / Nothing / Unit trong Scala


95

Tôi vừa đọc: http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

Theo như tôi hiểu, Nulllà một đặc điểm và trường hợp duy nhất của nó là null.

Khi một phương thức nhận đối số Null, thì chúng ta chỉ có thể chuyển nó một Nulltham chiếu hoặc nulltrực tiếp, chứ không phải bất kỳ tham chiếu nào khác, ngay cả khi nó là null ( nullString: String = nullví dụ).

Tôi chỉ tự hỏi trong những trường hợp sử dụng Nullđặc điểm này có thể hữu ích. Ngoài ra còn có đặc điểm Không có gì mà tôi thực sự không thấy bất kỳ ví dụ nào nữa.


Tôi thực sự không hiểu sự khác biệt giữa việc sử dụng Không có gì và Đơn vị làm kiểu trả về là gì, vì cả hai đều không trả về bất kỳ kết quả nào, làm thế nào để biết nên sử dụng kết quả nào khi tôi có một phương thức thực hiện ghi nhật ký?


Bạn có sử dụng Đơn vị / Null / Không có gì khác ngoài kiểu trả về không?

Câu trả lời:


80

Bạn chỉ sử dụng Không có gì nếu phương thức không bao giờ trả về (có nghĩa là nó không thể hoàn thành bình thường bằng cách trả về, nó có thể ném ra một ngoại lệ). Không có gì là không bao giờ được khởi tạo và ở đó vì lợi ích của hệ thống kiểu (trích lời James Iry: "Lý do Scala có kiểu dưới cùng được gắn với khả năng thể hiện phương sai trong các tham số kiểu" ). Từ bài viết bạn đã liên kết đến:

Một cách sử dụng khác của Nothing là kiểu trả về cho các phương thức không bao giờ trả về. Điều đó có nghĩa nếu bạn nghĩ về nó. Nếu kiểu trả về của một phương thức là Không có gì và hoàn toàn không tồn tại trường hợp Không có gì, thì phương thức như vậy không bao giờ được trả về.

Phương thức ghi nhật ký của bạn sẽ trả về Đơn vị. Có một Đơn vị giá trị để nó thực sự có thể được trả lại. Từ tài liệu API :

Đơn vị là một kiểu con của scala.AnyVal. Chỉ có một giá trị kiểu Đơn vị, (), và nó không được đại diện bởi bất kỳ đối tượng nào trong hệ thống thời gian chạy cơ bản. Một phương thức có kiểu trả về Unit tương tự như một phương thức Java được khai báo là void.


2
Cảm ơn, bởi "không bao giờ trở lại" bạn có nghĩa là cuộc gọi được chặn vô thời hạn (ví dụ phương pháp khởi động của lịch trình công việc?)
Sebastien Lorber

3
@Sabastien: nó không trở lại bình thường, nó có thể tạo ra một ngoại lệ (xem james-iry.blogspot.com/2009/08/… ). nếu lệnh gọi chặn chỉ kết thúc bằng việc ném một ngoại lệ thì điều đó sẽ được tính. cảm ơn cho câu hỏi, điều này cần làm rõ.
Nathan Hughes

18

Bài báo bạn trích dẫn có thể gây hiểu lầm. Các Nullloại là có để tương thích với các máy ảo Java , và Java nói riêng.

Chúng ta phải xem xét Scala đó :

  • là hướng đối tượng hoàn toàn: mọi giá trị là một đối tượng
  • được nhập mạnh: mọi giá trị phải có một kiểu
  • cần xử lý các nulltham chiếu để truy cập, ví dụ: thư viện Java và mã

do đó, nó trở nên cần thiết để xác định một kiểu cho nullgiá trị, đó là Nullđặc điểm và có nullnhư là trường hợp duy nhất của nó.

Không có gì đặc biệt hữu ích trong Nullkiểu trừ khi bạn là kiểu hệ thống hoặc bạn đang phát triển trên trình biên dịch. Đặc biệt, tôi không thể thấy bất kỳ lý do hợp lý nào để xác định Nulltham số kiểu cho một phương thức, vì bạn không thể truyền bất kỳ thứ gì ngoàinull


đó là sự thật, vì vậy cuối cùng không có cách sử dụng khác của Null?
Sebastien Lorber

@SebastienLorber đã chỉnh sửa câu trả lời. Tôi thực sự không thể thấy bất kỳ cách sử dụng nào cho nhà phát triển trung bình. Có thể ai đó khác có thể nghĩ ra điều gì đó hữu ích.
Pagoda_5b

Cảm ơn vì điều đó. Nếu chúng ta biết lý do của những điều này, chúng ta hiểu chúng, nếu không chúng ta sẽ nhớ chúng.
Sreekar

Null hữu ích khi bạn có một tham số kiểu và có thể muốn trả về null như trong câu hỏi và câu trả lời này , vì bạn không khuyến khích sử dụng null trong scala, nó hiếm khi xuất hiện, mặc dù vậy, có thể có các cách sử dụng khác trong hệ thống kiểu
Daniel Carlsson

15

Bạn có sử dụng Đơn vị / Null / Không có gì khác ngoài kiểu trả về không?


Unit có thể được sử dụng như thế này:

def execute(code: => Unit):Unit = {
  // do something before
  code
  // do something after
}

Điều này cho phép bạn chuyển một khối mã tùy ý được thực thi.


Nullcó thể được sử dụng làm kiểu dưới cùng cho bất kỳ giá trị nào có thể làm trống. Một ví dụ là thế này:

implicit def zeroNull[B >: Null] =
    new Zero[B] { def apply = null }

Nothing được sử dụng trong định nghĩa của None

object None extends Option[Nothing]

Điều này cho phép bạn gán một Nonecho bất kỳ loại nào OptionNothing'mở rộng' mọi thứ.

val x:Option[String] = None

Đồng ý. Đối với việc sử dụng Đơn vị của bạn, bạn có thể đã sử dụng một kiểu chung để lệnh thực thi có thể trả về kiểu chung này nếu khối mã của bạn trả về thứ gì đó khác với đơn vị.
Sebastien Lorber

Như @drexin đã nói trong một bình luận về một câu trả lời khác, nó chủ yếu được sử dụng để biểu thị một tác dụng phụ.
EECOLOR

6

nếu bạn sử dụng Nothing, không có việc gì phải làm (bao gồm bảng điều khiển in) nếu bạn làm gì đó, hãy sử dụng loại đầu raUnit

object Run extends App {
  //def sayHello(): Nothing = println("hello?")
  def sayHello(): Unit = println("hello?")
  sayHello()
}

... thì làm thế nào để sử dụng Nothing?

trait Option[E]
case class Some[E](value: E) extends Option[E]
case object None extends Option[Nothing]

1
Ngoài ra, Etrong Optioncó để được ở vị trí hiệp biến: trait Option[+E]để cho phép những thứ nhưval x: Option[Int] = None
vim

5

Tôi chưa bao giờ thực sự sử dụng Nullloại, nhưng bạn sử dụng Unit, nơi bạn sẽ sử dụng java void. Nothinglà một kiểu đặc biệt, vì như Nathan đã đề cập, không thể có trường hợp nào của Nothing. Nothinglà một loại được gọi là dưới cùng, có nghĩa là nó là một loại phụ của bất kỳ loại nào khác. Đây (và tham số kiểu tương phản) là lý do tại sao bạn có thể thêm bất kỳ giá trị nào vào Nil- là a List[Nothing]- và danh sách sau đó sẽ thuộc loại phần tử này. Nonecòn nếu thuộc loại Option[Nothing]. Mọi nỗ lực truy cập các giá trị bên trong một vùng chứa như vậy sẽ ném ra một ngoại lệ, vì đó là cách hợp lệ duy nhất để trả về từ một phương thức của kiểu Nothing.


cảm ơn Tôi không biết rằng Không có mở rộng Tùy chọn [Không có gì]. Nó có ý nghĩa trong một số sử dụng Generics nơi một subtype có thể sử dụng Không có gì (tôi đoán thật khó để tìm thấy một dụ cho Null và đơn vị ...)
Sebastien Lorber

Đơn vị được sử dụng, khi các tác dụng phụ xảy ra, ví dụ đơn nguyên IO có thể là loại IO[Unit]để in ra bảng điều khiển và tương tự.
drexin

Vâng, không bao giờ sử dụng IO đơn nguyên nó làm cho tinh thần để sử dụng nó với Unit (và có lẽ không có gì nếu nó nó là một số hoạt động IO sản xuất một dòng vô hạn?)
Sebastien Lorber

Không, không có gì vô nghĩa ở đó.
drexin

3

Không có gì thường được sử dụng ngầm. Trong đoạn mã dưới đây, val b: Boolean = if (1 > 2) false else throw new RuntimeException("error") các khác khoản là loại có gì , đó là một lớp con của Boolean (cũng như bất kỳ AnyVal khác). Do đó, toàn bộ phép gán hợp lệ cho trình biên dịch, mặc dù mệnh đề else không thực sự trả về bất cứ điều gì.


1

Đây là một ví dụ về Nothingtừ scala.predef:

  def ??? : Nothing = throw new NotImplementedError

Trong trường hợp bạn không quen (và công cụ tìm kiếm không thể tìm kiếm trên đó) ??? là chức năng giữ chỗ của Scala cho bất kỳ thứ gì chưa được triển khai. Giống như của Kotlin TODO.

Bạn có thể sử dụng thủ thuật tương tự khi tạo các đối tượng giả: ghi đè các phương thức không sử dụng bằng một notUsedphương thức tùy chỉnh . Ưu điểm của việc không sử dụng ???là bạn sẽ không nhận được cảnh báo biên dịch cho những thứ bạn không bao giờ có ý định thực hiện.


0

Về lý thuyết phạm trù Không có gìđối tượng ban đầuĐơn vịđối tượng đầu cuối .

https://en.wikipedia.org/wiki/Initial_and_terminal_objects

Các đối tượng ban đầu còn được gọi là coterminal hoặc Universal , và các đối tượng cuối cũng được gọi là cuối cùng .

Nếu một đối tượng là cả hai ban đầuthiết bị đầu cuối , nó được gọi là một đối tượng không hay đối tượng.

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.