Call-by-Name: => Type
=> Type
โน้ตย่อมาจากการเรียกร้องโดยชื่อซึ่งเป็นหนึ่งในหลายวิธีที่พารามิเตอร์สามารถผ่าน หากคุณไม่คุ้นเคยกับพวกเขาฉันขอแนะนำให้สละเวลาอ่านบทความวิกิพีเดียแม้ว่าทุกวันนี้ส่วนใหญ่จะเป็นการโทรตามค่าและการอ้างอิงโดยการโทร
หมายความว่าอะไรที่ส่งผ่านถูกแทนที่สำหรับชื่อค่าภายในฟังก์ชัน ตัวอย่างเช่นใช้ฟังก์ชันนี้:
def f(x: => Int) = x * x
ถ้าฉันเรียกมันว่าอย่างนี้
var y = 0
f { y += 1; y }
จากนั้นโค้ดจะทำงานเช่นนี้
{ y += 1; y } * { y += 1; y }
แม้ว่านั่นจะทำให้เกิดสิ่งที่เกิดขึ้นหากมีการระบุชื่อที่ขัดแย้งกัน ในการโทรตามชื่อดั้งเดิมกลไกที่เรียกว่าการทดแทนการหลีกเลี่ยงการดักจับเกิดขึ้นเพื่อหลีกเลี่ยงการปะทะกันของชื่อ อย่างไรก็ตามใน Scala สิ่งนี้จะถูกนำไปใช้ในอีกทางหนึ่งด้วยชื่อผลลัพธ์แบบเดียวกันภายในพารามิเตอร์ที่ไม่สามารถอ้างถึงหรือตัวระบุเงาในฟังก์ชันที่เรียกใช้
มีประเด็นอื่น ๆ ที่เกี่ยวข้องกับชื่อเรียกที่ฉันจะพูดถึงหลังจากอธิบายอีกสองประเด็น
ฟังก์ชั่น 0-arity: () => Type
ไวยากรณ์ยืนสำหรับประเภทของที่() => Type
Function0
นั่นคือฟังก์ชั่นที่ไม่มีพารามิเตอร์และส่งคืนบางสิ่ง สิ่งนี้เทียบเท่ากับการเรียกใช้เมธอดsize()
- มันไม่มีพารามิเตอร์และส่งกลับตัวเลข
อย่างไรก็ตามเป็นที่น่าสนใจว่าวากยสัมพันธ์นี้คล้ายกับไวยากรณ์ของฟังก์ชันนิรนามซึ่งเป็นสาเหตุของความสับสน ตัวอย่างเช่น,
() => println("I'm an anonymous function")
เป็นฟังก์ชันที่ไม่ระบุชื่อตามตัวอักษรของ arity 0 ซึ่งเป็นประเภท
() => Unit
ดังนั้นเราสามารถเขียน:
val f: () => Unit = () => println("I'm an anonymous function")
มันเป็นสิ่งสำคัญที่จะไม่สับสนประเภทที่มีค่าอย่างไรก็ตาม
หน่วย => ประเภท
นี่เป็นเพียงแค่ a Function1
พารามิเตอร์ที่มีประเภทUnit
แรก วิธีการอื่น ๆ ที่จะเขียนมันจะเป็นหรือ(Unit) => Type
Function1[Unit, Type]
มันคือ ... นี่ไม่น่าจะเป็นอย่างที่เราต้องการ Unit
วัตถุประสงค์หลักของประเภทจะระบุค่าหนึ่งไม่สนใจจึงไม่ได้ทำให้ความรู้สึกที่จะได้รับค่าที่
ยกตัวอย่างเช่น
def f(x: Unit) = ...
เราจะทำx
อะไรได้บ้าง? มีเพียงค่าเดียวเท่านั้นดังนั้นจึงไม่จำเป็นต้องได้รับ การใช้งานที่เป็นไปได้อย่างหนึ่งคือการผูกมัดฟังก์ชันที่ส่งคืนUnit
:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
เนื่องจากandThen
มีการกำหนดไว้เท่านั้นFunction1
และฟังก์ชั่นที่เรากำลังนำเสนอกลับมาUnit
เราจึงต้องกำหนดให้เป็นประเภทFunction1[Unit, Unit]
เพื่อให้สามารถเชื่อมโยงได้
แหล่งที่มาของความสับสน
แหล่งที่มาของความสับสนแรกกำลังคิดความคล้ายคลึงกันระหว่างชนิดและตัวอักษรที่มีอยู่สำหรับฟังก์ชัน 0-arity ยังมีอยู่สำหรับการโทรตามชื่อ ในคำอื่น ๆ คิดว่าเพราะ
() => { println("Hi!") }
เป็นตัวอักษรสำหรับ() => Unit
แล้ว
{ println("Hi!") }
=> Unit
จะเป็นตัวอักษรสำหรับ มันไม่ใช่. นั่นคือบล็อกของรหัสไม่ใช่ตัวอักษร
แหล่งที่มาของความสับสนอื่นคือค่าUnit
ประเภทนั้นถูกเขียนซึ่งดูเหมือนรายการพารามิเตอร์ 0-arity (แต่ไม่ใช่)()
case class Scheduled(time: Int)(callback: => Unit)
โดยชื่ออีกอย่างหนึ่งคือการใส่ไว้ในรายการพารามิเตอร์รองเช่น ใช้งานได้เนื่องจากรายการพารามิเตอร์รองไม่ได้เปิดเผยต่อสาธารณะและไม่รวมอยู่ในการสร้างequals
/hashCode
วิธีการ