คำหลัก "ใหม่" ใน Scala


96

ฉันมีคำถามง่ายๆ - เราควรใช้คีย์เวิร์ดใหม่เมื่อสร้างอ็อบเจกต์ใน Scala เมื่อใด เมื่อเราพยายามสร้างอินสแตนซ์วัตถุ Java เท่านั้นหรือไม่?

คำตอบ:


146

ใช้newคำสำคัญเมื่อคุณต้องการอ้างถึงclassตัวสร้างของตัวเอง:

class Foo { }

val f = new Foo

ละเว้นnewหากคุณกำลังอ้างถึงapplyวิธีการของวัตถุที่แสดงร่วม:

class Foo { }
object Foo {
    def apply() = new Foo
}

// Both of these are legal
val f = Foo()
val f2 = new Foo

หากคุณสร้างคลาสเคส:

case class Foo()

Scala แอบสร้างวัตถุคู่ใจให้คุณโดยเปลี่ยนเป็นสิ่งนี้:

class Foo { }
object Foo {
    def apply() = new Foo
}

ดังนั้นคุณสามารถทำได้

f = Foo()

สุดท้ายโปรดทราบว่าไม่มีกฎใดที่บอกว่าapply เมธอดที่แสดงร่วมจะต้องเป็นพร็อกซีสำหรับตัวสร้าง:

class Foo { }
object Foo {
    def apply() = 7
}

// These do different things
> println(new Foo)
test@5c79cc94
> println(Foo())
7

และเนื่องจากคุณได้กล่าวถึงคลาส Java: ใช่ - คลาส Java ไม่ค่อยมีอ็อบเจ็กต์ร่วมกับapplyเมธอดดังนั้นคุณต้องใช้newและคอนสตรัคเตอร์ของคลาสจริง


1
คลาส Java ไม่สามารถมีอ็อบเจ็กต์ร่วมได้ สามารถมีอ็อบเจ็กต์ที่สามารถทำงานเป็น Factory สำหรับคลาส Java ได้ แต่อ็อบเจ็กต์นี้ไม่ใช่อ็อบเจ็กต์คู่หู
kiritsuku

@Antoras เนื่องจากคลาส Scala คอมไพล์เป็น Java bytecode และสามารถเผยแพร่ในรูปแบบที่คอมไพล์ได้ Scala สามารถบอกความแตกต่างระหว่างสหาย Scala จริงและคลาสที่ชื่อ Foo $ ด้วยสมาชิก MODULE $ แบบคงที่ได้หรือไม่
Owen

1
ฉันคิดว่า scalac อาจแตกต่างกันได้เนื่องจากมีการระบุว่าวัตถุที่แสดงร่วมจะต้องถูกประกาศในไฟล์เดียวกับคลาสที่แสดงร่วมกัน เนื่องจาก "คุณสมบัติ" ที่แสดงร่วมมีอยู่เฉพาะใน Scala และไม่ได้อยู่ในสเกลาระดับ Bytecode จึงต้องตรวจสอบรหัส Scala ไม่ใช่ Bytecode เพื่อให้แน่ใจว่าเป็นไปตามข้อกำหนด
kiritsuku

1
ตัวอย่างของคลาส Java ที่ไม่ใช้คีย์เวิร์ดใหม่ใน Scala หรือไม่?
Bober 02

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

16

เมื่อเราพยายามสร้างอินสแตนซ์วัตถุ java เท่านั้นหรือไม่?

ไม่ใช่เลย. มีสองกรณีทั่วไปเมื่อคุณเลือกnewใน scala ด้วยอ็อบเจ็กต์ซิงเกิลตัน (ซึ่งมักใช้ในการจัดเก็บฟังก์ชันคงที่และเป็นโรงงานที่คล้ายกับสิ่งที่คุณอาจเห็นใน java):

scala> object LonelyGuy { def mood = "sad" }
defined module LonelyGuy

scala> LonelyGuy
res0: LonelyGuy.type = LonelyGuy$@3449a8

scala> LonelyGuy.mood
res4: java.lang.String = sad

ด้วยคลาสเคส (ที่จริงแล้วข้างล่างมี class + object = รูปแบบการแสดงร่วมเช่นมีคลาสและอ็อบเจ็กต์ที่มีชื่อเดียวกัน):

scala> case class Foo(bar: String) 
defined class Foo


scala> Foo("baz")
res2: Foo = Foo(baz)

ดังนั้นเมื่อคุณทำงานกับคลาสง่ายๆกฎจะเหมือนกับ Java

scala> class Foo(val bar: String) 
defined class Foo

scala> new Foo("baz")
res0: Foo = Foo@2ad6a0

// will be a error 
scala> Foo("baz")
<console>:8: error: not found: value Foo
       Foo("baz")

โบนัสมีคลาสที่ไม่ระบุตัวตนในสกาล่าซึ่งสามารถสร้างได้ดังนี้:

scala> new { val bar = "baz" }
res2: java.lang.Object{val bar: java.lang.String} = $anon$1@10ee5b8

scala> res2.bar
res3: java.lang.String = baz

1
คุณโอเคที่นั่นไหม?
Jacob B

0

เมื่อเราพยายามสร้างอินสแตนซ์วัตถุ Java เท่านั้นหรือไม่?

ด้วย Scala 3 (ซึ่งน่าจะออกกลางปี ​​2020 แปดปีต่อมา) อิงจาก Dotty : never

Scala 3 จะลดลง " new" เช่นเดียวกับในชุดข้อความนี้

แอปพลิเคชันผู้สร้างอนุญาตให้ใช้ไวยากรณ์การเรียกฟังก์ชันอย่างง่ายเพื่อสร้างอินสแตนซ์ของคลาสแม้ว่าจะไม่มีการนำวิธีการใช้งานมาใช้ก็ตาม

ตัวอย่าง:

class StringBuilder(s: String) {
   def this() = this(s)
}

StringBuilder("abc")  // same as new StringBuilder("abc")
StringBuilder()       // same as new StringBuilder()

แอปพลิเคชันผู้สร้างสรุปฟังก์ชันการทำงานที่มีให้สำหรับคลาสเคสเท่านั้น แต่กลไกการทำงานนี้แตกต่างกันเล็กน้อย
แทนที่จะเป็นวิธีการที่สร้างขึ้นโดยอัตโนมัติใช้เราเพิ่มการตีความที่เป็นไปได้ใหม่ ๆ f(args)ในการเรียกใช้ฟังก์ชัน

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