สกาลาคอนสตรัคเตอร์เกิน?


คำตอบ:


186

เป็นเรื่องที่ควรค่าแก่การกล่าวถึงอย่างชัดเจนว่า Auxiliary Constructor ใน Scala ต้องเรียกคำตอบของตัวสร้างหลัก (เช่นเดียวกับใน landon9720's) หรือตัวสร้างเสริมอื่นจากคลาสเดียวกันเป็นการกระทำครั้งแรก พวกเขาไม่สามารถเรียกคอนสตรัคเตอร์ของซูเปอร์คลาสอย่างชัดเจนหรือโดยปริยายเท่าที่ทำได้ใน Java สิ่งนี้ทำให้มั่นใจได้ว่าตัวสร้างหลักเป็นจุดเดียวของการเข้าสู่คลาส

class Foo(x: Int, y: Int, z: String) {  
  // default y parameter to 0  
  def this(x: Int, z: String) = this(x, 0, z)   
  // default x & y parameters to 0
  // calls previous auxiliary constructor which calls the primary constructor  
  def this(z: String) = this(0, z);   
}

@Jon McAuliffe: ตัวอย่างที่ไม่ดี? หากไม่มีตัวสร้างที่สองและสามผู้ใช้ยังคงสามารถโทรหาได้new Foo(x=2,z=4)และnew Foo(z=5)ถ้าคุณเปลี่ยนบรรทัดแรกเป็นclass Foo(x: Int = 0, y: Int = 0, z: String) {
user2987828

อาร์กิวเมนต์ที่มีชื่อ / ค่าเริ่มต้นไม่มาถึงจนกว่า Scala 2.8
Jon McAuliffe

2
ควรกล่าวถึงวิธีการใช้ตัวสร้างโอเวอร์โหลด ไม่ใช่เรื่องเล็กน้อยที่newคีย์เวิร์ดจำเป็นสำหรับคลาสเคส
Readren


16

ตั้งแต่ Scala 2.8.0 คุณยังสามารถมีค่าเริ่มต้นสำหรับพารามิเตอร์ contructor และ method แบบนี้

scala> class Foo(x:Int, y:Int = 0, z:Int=0) {                           
     | override def toString() = { "Foo(" + x + ", " + y + ", " + z + ")" }
     | }
defined class Foo

scala> new Foo(1, 2, 3)                                                    
res0: Foo = Foo(1, 2, 3)

scala> new Foo(4)                                                          
res1: Foo = Foo(4, 0, 0)

พารามิเตอร์ที่มีค่าดีฟอลต์ต้องมาตามหลังพารามิเตอร์ที่ไม่มีค่าดีฟอลต์ในรายการพารามิเตอร์


3
สิ่งนี้ใช้ไม่ได้กับค่าเริ่มต้นที่ไม่สำคัญ จึงclass Foo(val x:Int, y:Int=2*x)ไม่ทำงาน
subsub

@ Jörgen Lundberg: คุณเขียนพารามิเตอร์ด้วยค่าเริ่มต้นต้องมาตามหลังค่าที่ไม่มีค่าเริ่มต้นในรายการพารามิเตอร์ มันเป็นความผิดจะพิมพ์new Foo(x=2,z=4) Foo(2,0,4)
user2987828

@ user2987828 สิ่งที่ฉันหมายถึงคือคุณไม่สามารถเขียน Foo ใหม่ (12, x = 2) คุณต้องเขียน Foo ใหม่ (x = 2, 12) คุณสามารถเขียน Foo ใหม่ (12, y = 2) จากนั้นคุณจะได้รับ Foo (12, 2, 0)
Jörgen Lundberg

10

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

ใน Scala คุณไม่สามารถโอเวอร์โหลดคอนสตรัคเตอร์ได้ แต่สามารถทำได้ด้วยฟังก์ชัน

นอกจากนี้หลายคนเลือกที่จะทำให้applyฟังก์ชันของอ็อบเจ็กต์ร่วมเป็นโรงงานสำหรับคลาสที่เกี่ยวข้อง

การทำให้คลาสนี้เป็นนามธรรมและการโอเวอร์โหลดapplyฟังก์ชันในการใช้งาน - อินสแตนซ์คลาสนี้คุณมี "ตัวสร้าง" ที่โอเวอร์โหลด:

abstract class Expectation[T] extends BooleanStatement {
    val expected: Seq[T]
    …
}

object Expectation {
    def apply[T](expd:     T ): Expectation[T] = new Expectation[T] {val expected = List(expd)}
    def apply[T](expd: Seq[T]): Expectation[T] = new Expectation[T] {val expected =      expd }

    def main(args: Array[String]): Unit = {
        val expectTrueness = Expectation(true)
        …
    }
}

หมายเหตุที่ผมกำหนดอย่างชัดเจนในแต่ละapplyที่จะกลับอื่นก็จะกลับมาเป็นเป็ดพิมพ์Expectation[T]Expectation[T]{val expected: List[T]}


0

ลองทำตามนี้

class A(x: Int, y: Int) {
  def this(x: Int) = this(x, x)
  def this() = this(1)
  override def toString() = "x=" + x + " y=" + y
  class B(a: Int, b: Int, c: String) {
    def this(str: String) = this(x, y, str)
    override def toString() =
      "x=" + x + " y=" + y + " a=" + a + " b=" + b + " c=" + c
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.