ฉันยังใหม่กับสกาล่าและฉันไม่สามารถหาtype
คำหลักได้มากนัก ฉันพยายามเข้าใจว่านิพจน์ต่อไปนี้อาจหมายถึงอะไร:
type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
FunctorType
นามแฝงบางประเภท แต่มีความหมายว่าอะไร
ฉันยังใหม่กับสกาล่าและฉันไม่สามารถหาtype
คำหลักได้มากนัก ฉันพยายามเข้าใจว่านิพจน์ต่อไปนี้อาจหมายถึงอะไร:
type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
FunctorType
นามแฝงบางประเภท แต่มีความหมายว่าอะไร
คำตอบ:
ใช่นามแฝงประเภท FunctorType
เป็นเพียงชวเลข
(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
ประเภทนามแฝงมักจะใช้เพื่อให้รหัสที่เหลือง่าย: ตอนนี้คุณสามารถเขียน
def doSomeThing(f: FunctorType)
ซึ่งจะแปลโดยคอมไพเลอร์เป็น
def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)
สิ่งนี้ช่วยในการหลีกเลี่ยงการกำหนดประเภทที่กำหนดเองมากมายที่เป็นเพียง tuples หรือฟังก์ชั่นที่กำหนดไว้ในประเภทอื่นเช่น
นอกจากนี้ยังมีกรณีการใช้งานที่น่าสนใจอื่น ๆ อีกหลายกรณีtype
ดังที่อธิบายไว้ในบทของการเขียนโปรแกรมใน Scalaนี้
จริงๆแล้วtype
คำหลักใน Scala สามารถทำได้มากกว่าแค่การใช้นามแฝงประเภทที่ซับซ้อนไปเป็นชื่อที่สั้นกว่า แนะนำสมาชิกประเภท
ดังที่คุณทราบคลาสสามารถมีสมาชิกฟิลด์และสมาชิกเมธอด สกาล่ายังให้ชั้นเรียนมีสมาชิกประเภทด้วย
ในกรณีเฉพาะของคุณtype
คือการแนะนำนามแฝงที่ช่วยให้คุณเขียนโค้ดที่กระชับยิ่งขึ้น ระบบประเภทเพียงแทนที่นามแฝงด้วยประเภทจริงเมื่อดำเนินการตรวจสอบประเภท
แต่คุณสามารถมีอะไรเช่นนี้
trait Base {
type T
def method: T
}
class Implementation extends Base {
type T = Int
def method: T = 42
}
เช่นเดียวกับสมาชิกคนอื่น ๆ ของคลาสสมาชิกประเภทยังสามารถเป็นนามธรรม (คุณเพียงแค่ไม่ได้ระบุค่าที่แท้จริงของพวกเขา) และสามารถถูกแทนที่ในการใช้งาน
สมาชิกประเภทสามารถดูได้เป็นข้อมูลทั่วไปสองเท่าเนื่องจากสิ่งต่าง ๆ ที่คุณสามารถนำไปใช้กับข้อมูลทั่วไปสามารถแปลเป็นสมาชิกประเภทนามธรรมได้
ใช่พวกมันสามารถใช้แทนนามแฝงได้ แต่อย่า จำกัด เพียงแค่นี้เพราะมันเป็นคุณสมบัติที่ทรงพลังของระบบพิมพ์ของสกาล่า
โปรดดูคำตอบที่ยอดเยี่ยมสำหรับรายละเอียดเพิ่มเติม:
ฉันชอบคำตอบจาก Roland Ewaldตั้งแต่เขาอธิบายด้วยกรณีการใช้งานง่าย ๆ ของ alias ประเภทและสำหรับรายละเอียดเพิ่มเติมแนะนำการกวดวิชาที่ดีมาก อย่างไรก็ตามเนื่องจากมีการแนะนำกรณีการใช้งานอื่นในโพสต์นี้ชื่อประเภทสมาชิกฉันต้องการพูดถึงกรณีการใช้งานจริงมากที่สุดของมันซึ่งฉันชอบมาก: (ส่วนนี้นำมาจากที่นี่ :)
ประเภทนามธรรม:
type T
T ด้านบนบอกว่าประเภทนี้ที่จะใช้ไม่เป็นที่รู้จักและขึ้นอยู่กับคลาสย่อยของคอนกรีตมันจะถูกกำหนด วิธีที่ดีที่สุดในการทำความเข้าใจแนวคิดการเขียนโปรแกรมให้ตัวอย่าง: สมมติว่าคุณมีสถานการณ์ต่อไปนี้:
ที่นี่คุณจะได้รับข้อผิดพลาดในการคอมไพล์เนื่องจากวิธีการกินในคลาส Cow และ Tiger จะไม่แทนที่วิธีการกินในคลาส Animal เนื่องจากชนิดพารามิเตอร์แตกต่างกัน มันเป็นหญ้าในวัวชั้นและเนื้อในชั้นเสือกับอาหารในชั้นเรียนสัตว์ซึ่งเป็นซุปเปอร์คลาสและคลาสย่อยทั้งหมดต้องเป็นไปตาม
ตอนนี้กลับไปที่ประเภท abstraction โดยไดอะแกรมต่อไปนี้และเพียงเพิ่ม abstraction ประเภทคุณสามารถกำหนดประเภทของอินพุตในคลาสย่อยเองได้
ตอนนี้ดูรหัสต่อไปนี้:
val cow1: Cow = new Cow
val cow2: Cow = new Cow
cow1 eat new cow1.SuitableFood
cow2 eat new cow1.SuitableFood
val tiger: Tiger = new Tiger
cow1 eat new tiger.SuitableFood // Compiler error
คอมไพเลอร์มีความสุขและเราปรับปรุงการออกแบบของเรา เราสามารถเลี้ยงวัวของเราด้วยวัวเหมาะสำหรับอาหารและคอมไพเลอร์ป้องกันไม่ให้เราเลี้ยงวัวด้วยอาหารที่เหมาะสมกับเสือ แต่ถ้าเราต้องการสร้างความแตกต่างระหว่างชนิดของวัว 1 อาหารที่เหมาะสมและอาหารวัว 2 กล่าวอีกนัยหนึ่งมันจะมีประโยชน์มากในบางสถานการณ์หากเส้นทางที่เราไปถึงประเภท (แน่นอนผ่านทางวัตถุ) นั้นสำคัญ ด้วยคุณสมบัติขั้นสูงในสกาล่ามันเป็นไปได้:
ประเภทพา ธ ที่ขึ้นอยู่กับ: วัตถุสกาล่าสามารถมีประเภทเป็นสมาชิก ความหมายของประเภทขึ้นอยู่กับเส้นทางที่คุณใช้ในการเข้าถึง เส้นทางถูกกำหนดโดยการอ้างอิงไปยังวัตถุ (aka ตัวอย่างของคลาส) ในการใช้สถานการณ์นี้คุณต้องกำหนดคลาส Grass ภายในวัวเช่น Cow คือคลาสภายนอกและ Grass เป็นคลาสภายใน โครงสร้างจะเป็นดังนี้:
class Cow extends Animal {
class Grass extends Food
type SuitableFood = Grass
override def eat(food: this.SuitableFood): Unit = {}
}
class Tiger extends Animal {
class Meat extends Food
type SuitableFood = Meat
override def eat(food: this.SuitableFood): Unit = {}
}
ตอนนี้ถ้าคุณพยายามที่จะรวบรวมรหัสนี้:
1. val cow1: Cow = new Cow
2. val cow2: Cow = new Cow
3. cow1 eat new cow1.SuitableFood
4. cow2 eat new cow1.SuitableFood // compilation error
ในบรรทัดที่ 4 คุณจะเห็นข้อผิดพลาดเนื่องจาก Grass เป็นคลาสภายในของ Cow ดังนั้นในการสร้างตัวอย่างของ Grass เราจำเป็นต้องมีวัตถุวัวและวัตถุวัวนี้จะกำหนดเส้นทาง ดังนั้นวัตถุ 2 ตัวทำให้เกิดเส้นทางที่แตกต่างกัน 2 แบบ ในสถานการณ์นี้ Cow2 เพียงต้องการกินอาหารที่สร้างขึ้นโดยเฉพาะสำหรับมัน ดังนั้น:
cow2 eat new cow2.SuitableFood
ตอนนี้ทุกคนมีความสุข :-)
เพียงตัวอย่างเพื่อดูวิธีใช้ "type" เป็นนามแฝง:
type Action = () => Unit
คำนิยามข้างต้นกำหนดการกระทำที่จะเป็นนามแฝงของประเภทของขั้นตอน (วิธีการ) ที่ใช้รายการพารามิเตอร์ที่ว่างเปล่าและหน่วยที่กลับมา