การใช้งานของ Null / Nothing / Unit ใน Scala


95

ฉันเพิ่งอ่าน: http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

เท่าที่ผมเข้าใจคือลักษณะและเพียงตัวอย่างของมันคือNullnull

เมื่อเมธอดใช้อาร์กิวเมนต์ Null เราสามารถส่งต่อได้เฉพาะการNullอ้างอิงหรือnullโดยตรง แต่ไม่สามารถอ้างอิงอื่น ๆ ได้แม้ว่าจะเป็นโมฆะก็ตาม ( nullString: String = nullเช่น)

ฉันแค่สงสัยว่าในกรณีNullใดบ้างที่ใช้ลักษณะนี้จะมีประโยชน์ นอกจากนี้ยังมีลักษณะ Nothing ที่ฉันไม่เห็นตัวอย่างอีกต่อไป


ฉันไม่เข้าใจจริงๆว่าความแตกต่างระหว่างการใช้ Nothing และ Unit เป็นประเภทการส่งคืนคืออะไรเนื่องจากทั้งสองไม่ส่งคืนผลลัพธ์ใด ๆ จะทราบได้อย่างไรว่าจะใช้วิธีใดเมื่อฉันมีวิธีการที่ดำเนินการบันทึก


คุณมีการใช้งานของ Unit / Null / Nothing เป็นอย่างอื่นนอกเหนือจากประเภทผลตอบแทนหรือไม่

คำตอบ:


80

คุณจะใช้ Nothing ก็ต่อเมื่อเมธอดไม่คืนค่า (หมายความว่าไม่สามารถดำเนินการได้ตามปกติโดยการส่งคืนอาจทำให้เกิดข้อยกเว้น) ไม่มีสิ่งใดที่ไม่เคยสร้างอินสแตนซ์และมีไว้เพื่อประโยชน์ของระบบ type (เพื่ออ้างถึง James Iry: "เหตุผลที่ Scala มีประเภทด้านล่างนั้นเชื่อมโยงกับความสามารถในการแสดงความแปรปรวนของพารามิเตอร์ประเภท" ) จากบทความที่คุณเชื่อมโยงถึง:

การใช้ Nothing อีกวิธีหนึ่งเป็นประเภทการส่งคืนสำหรับวิธีการที่ไม่มีวันกลับมา มันสมเหตุสมผลถ้าคุณคิดเกี่ยวกับมัน หากประเภทการส่งคืนของเมธอดคือ Nothing และไม่มีอินสแตนซ์ของ Nothing อย่างแน่นอนดังนั้นวิธีการดังกล่าวจะต้องไม่ส่งคืน

วิธีการบันทึกของคุณจะส่งคืนหน่วย มีหน่วยค่าจึงสามารถส่งคืนได้จริง จากเอกสาร API :

หน่วยเป็นประเภทย่อยของสกาล่า AnyVal มีเพียงค่าเดียวของชนิด Unit, () และไม่ได้แสดงโดยอ็อบเจ็กต์ใด ๆ ในระบบรันไทม์พื้นฐาน เมธอดที่มีชนิดการส่งคืน Unit นั้นคล้ายคลึงกับวิธีการของ Java ซึ่งถูกประกาศว่าเป็นโมฆะ


2
ขอบคุณโดย "ไม่ส่งคืน" คุณหมายความว่าการโทรนั้นปิดกั้นโดยไม่มีกำหนด (สำหรับตัวอย่างวิธีการเริ่มต้นของตัวกำหนดตารางเวลางาน)
Sebastien Lorber

3
@ ซาบาสเตียน: มันไม่กลับมาปกติมันอาจทำให้เกิดข้อยกเว้นได้ (ดูjames-iry.blogspot.com/2009/08/… ) หากการโทรที่ปิดกั้นลงท้ายด้วยการโยนข้อยกเว้นก็จะนับ ขอบคุณสำหรับคำถามนี้จำเป็นต้องมีการชี้แจง
Nathan Hughes

18

บทความที่คุณอ้างอาจทำให้เข้าใจผิด Nullชนิดจะมีความเข้ากันได้กับเครื่องเสมือน Java , Java และโดยเฉพาะอย่างยิ่ง

เราต้องพิจารณาว่าScala :

  • เป็นเชิงวัตถุอย่างสมบูรณ์ทุกค่าคือวัตถุ
  • ถูกพิมพ์อย่างรุนแรง: ทุกค่าต้องมีประเภท
  • จำเป็นต้องจัดการnullการอ้างอิงเพื่อเข้าถึงตัวอย่างเช่นไลบรารีและโค้ด Java

ดังนั้นจึงจำเป็นต้องกำหนดประเภทสำหรับnullค่าซึ่งเป็นNullลักษณะและมีnullเป็นเพียงตัวอย่างเดียว

ไม่มีสิ่งใดที่มีประโยชน์อย่างยิ่งในNullประเภทนี้เว้นแต่คุณจะเป็นระบบประเภทหรือคุณกำลังพัฒนาบนคอมไพเลอร์ โดยเฉพาะอย่างยิ่งฉันไม่เห็นเหตุผลที่สมเหตุสมผลในการกำหนดNullพารามิเตอร์ประเภทสำหรับวิธีการเนื่องจากคุณไม่สามารถส่งผ่านอะไรได้เลยนอกจากnull


นั่นเป็นความจริงดังนั้นในที่สุดจึงไม่มีการใช้งานอื่น ๆ ของ Null?
Sebastien Lorber

@SebastienLorber แก้ไขคำตอบ ฉันไม่เห็นการใช้งานของนักพัฒนาทั่วไปเลย บางทีอาจมีคนอื่นคิดว่ามีประโยชน์
เจดีย์ _5b

ขอบคุณสำหรับสิ่งนี้. ถ้าเรารู้เหตุผลของเรื่องแบบนี้เราก็เข้าใจไม่เช่นนั้นเราก็จำได้
Sreekar

Null มีประโยชน์เมื่อคุณมีพารามิเตอร์ type และอาจต้องการคืนค่า null เช่นในคำถามและคำตอบนี้เนื่องจากคุณไม่ท้อถอยในการใช้ null ใน scala จึงไม่ค่อยเกิดขึ้น แต่อาจมีการใช้งานอื่น ๆ ในระบบ type เช่นกัน
Daniel Carlsson

15

คุณมีการใช้งานของ Unit / Null / Nothing เป็นอย่างอื่นนอกเหนือจากประเภทผลตอบแทนหรือไม่


Unit สามารถใช้งานได้ดังนี้:

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

สิ่งนี้ช่วยให้คุณสามารถส่งผ่านบล็อกรหัสที่ต้องการเพื่อดำเนินการ


Nullอาจถูกใช้เป็นประเภทล่างสุดสำหรับค่าใด ๆ ที่เป็นโมฆะ ตัวอย่างคือ:

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

Nothing ใช้ในคำจำกัดความของ None

object None extends Option[Nothing]

สิ่งนี้ช่วยให้คุณกำหนด a Noneให้กับประเภทใดก็ได้OptionเพราะNothing'ขยาย' ทุกอย่าง

val x:Option[String] = None

ตกลง. สำหรับการใช้งานหน่วยของคุณคุณสามารถใช้ประเภททั่วไปเพื่อให้การดำเนินการอาจส่งคืนประเภททั่วไปนี้หากบล็อกรหัสของคุณส่งคืนอย่างอื่นที่ไม่ใช่หน่วย
Sebastien Lorber

ดังที่ @drexin กล่าวในความคิดเห็นเกี่ยวกับคำตอบอื่นส่วนใหญ่จะใช้เพื่อแสดงถึงผลข้างเคียง
EECOLOR

6

หากคุณใช้Nothingไม่มีสิ่งที่ต้องทำ (รวมถึงคอนโซลการพิมพ์) หากคุณทำบางอย่างให้ใช้ประเภทเอาต์พุตUnit

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

... แล้วจะใช้ยังNothingไง?

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

1
นอกจากนี้Eในการที่Optionจะต้องอยู่ในตำแหน่งที่มีความสัมพันธ์ทางเพศ: trait Option[+E]เพื่อให้สิ่งต่างๆเช่นval x: Option[Int] = None
กลุ่ม

5

ฉันไม่เคยใช้จริงNullชนิด แต่คุณใช้ซึ่งคุณจะเกี่ยวกับการใช้งานจาวาUnit เป็นประเภทพิเศษเนื่องจากตามที่นาธานกล่าวไปแล้วจึงไม่มีตัวอย่างของไฟล์. เป็นสิ่งที่เรียกว่าประเภทล่างซึ่งหมายความว่าเป็นประเภทย่อยของประเภทอื่น ๆ นี่ (และพารามิเตอร์ประเภท contravariant) คือสาเหตุที่คุณสามารถนำหน้าค่าใด ๆ ไป- ซึ่งคือ- จากนั้นรายการจะเป็นประเภทองค์ประกอบนี้ ถ้าประเภท ความพยายามที่จะเข้าถึงค่าที่อยู่ภายในเช่นภาชนะที่ทุกคนจะโยนยกเว้นเนื่องจากว่ามันเป็นวิธีที่ถูกต้องเท่านั้นที่จะกลับมาจากวิธีการของชนิดvoidNothingNothingNothingNilList[Nothing]NoneOption[Nothing]Nothing


ขอบคุณฉันไม่รู้ว่าไม่มีขยาย Option [Nothing] มันสมเหตุสมผลในการใช้งานทั่วไปที่ประเภทย่อยสามารถใช้ Nothing ได้ (ฉันเดาว่ามันยากที่จะหาตัวอย่างสำหรับ Null และ Unit ... )
Sebastien Lorber

ใช้หน่วยเมื่อเกิดผลข้างเคียงตัวอย่างเช่น IO monad อาจเป็นประเภทIO[Unit]สำหรับการพิมพ์ไปยังคอนโซลและอื่น ๆ ที่คล้ายกัน
drexin

ใช่ไม่เคยใช้ IO monad มันสมเหตุสมผลที่จะใช้กับหน่วย (และอาจไม่มีอะไรเลยถ้าเป็นการดำเนินการของ IO ที่สร้างกระแสที่ไม่มีที่สิ้นสุด?)
Sebastien Lorber

ไม่ไม่มีอะไรสมเหตุสมผลที่นั่น
drexin

3

มักไม่มีสิ่งใดถูกใช้โดยปริยาย ในโค้ดด้านล่าง อื่นประโยคเป็นประเภทไม่มีอะไรซึ่งเป็น subclass ของบูลีน (เช่นเดียวกับ AnyVal อื่น ๆ ) ดังนั้นการมอบหมายทั้งหมดจึงใช้ได้กับคอมไพเลอร์แม้ว่าประโยคอื่นจะไม่ส่งคืนอะไรเลยval b: Boolean = if (1 > 2) false else throw new RuntimeException("error")


1

นี่คือตัวอย่างNothingจากscala.predef:

  def ??? : Nothing = throw new NotImplementedError

ในกรณีที่คุณไม่คุ้นเคย (และเครื่องมือค้นหาไม่สามารถค้นหาได้) ???เป็นฟังก์ชันตัวยึดตำแหน่งของ Scala สำหรับสิ่งที่ยังไม่ได้ใช้งาน เช่นเดียวกับ TODOKotlin

คุณสามารถใช้เคล็ดลับเดียวกันเมื่อมีการสร้างวัตถุจำลอง: แทนที่วิธีการที่ไม่ได้ใช้กับที่กำหนดเองnotUsedวิธีการ ข้อดีของการไม่ใช้???คือคุณจะไม่ได้รับคำเตือนในการคอมไพล์สำหรับสิ่งที่คุณไม่เคยตั้งใจจะนำไปใช้


0

ในแง่ของทฤษฎีประเภทไม่มีอะไรที่เป็นวัตถุเริ่มต้นและหน่วยเป็นวัตถุขั้ว

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

วัตถุเบื้องต้นจะเรียกว่าcoterminalหรือสากลและวัตถุขั้วจะเรียกว่าเป็นครั้งสุดท้าย

ถ้าวัตถุเป็นทั้งเบื้องต้นและขั้วก็จะเรียกว่าเป็นวัตถุเป็นศูนย์หรือnullวัตถุ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.