"Neues" Schlüsselwort in Scala

92

Ich habe eine sehr einfache Frage: Wann sollten wir das neue Schlüsselwort beim Erstellen von Objekten in Scala anwenden? Versuchen wir nur Java-Objekte zu instanziieren?

Bober02
quelle

Antworten:

143

Verwenden Sie das newSchlüsselwort, wenn Sie auf einen classeigenen Konstruktor verweisen möchten :

class Foo { }

val f = new Foo

Lassen newSie weg, wenn Sie sich auf die applyMethode des Begleitobjekts beziehen :

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

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

Wenn Sie eine Fallklasse erstellt haben:

case class Foo()

Scala erstellt heimlich ein Begleitobjekt für Sie und verwandelt es in Folgendes:

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

So können Sie tun

f = Foo()

Beachten Sie zum Schluss, dass es keine Regel gibt, die besagt, dass die Companion- apply Methode ein Proxy für den Konstruktor sein muss:

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

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

Und da Sie Java-Klassen erwähnt haben: Ja - Java-Klassen haben selten Begleitobjekte mit einer applyMethode, daher müssen Sie newden Konstruktor der eigentlichen Klasse verwenden.

Owen
quelle
1
Eine Java-Klasse kann niemals ein Begleitobjekt haben. Es kann ein Objekt haben, das als Factory für die Java-Klasse fungieren kann - aber dieses Objekt ist nicht das Begleitobjekt.
Kiritsuku
@Antoras Kann Scala den Unterschied zwischen einem tatsächlichen Scala-Begleiter und einer Klasse namens Foo $ mit einem statischen MODULE $ -Mitglied erkennen, da Scala-Klassen in Java-Bytecode kompiliert und in kompilierter Form verteilt werden können?
Owen
1
Ich denke, Scalac kann dies unterscheiden, da angegeben wird, dass ein Companion-Objekt in derselben Datei wie seine Companion-Klasse deklariert werden muss. Da die begleitende "Eigenschaft" nur in Scala und nicht auf Bytecode-Ebene vorhanden ist, muss Scalac den Scala-Code und nicht den Bytecode überprüfen, um sicherzustellen, dass die Spezifikation eingehalten wird.
Kiritsuku
1
Gibt es Beispiele für Java-Klassen, die in Scala KEIN neues Schlüsselwort verwenden?
Bober02
Auch die Methoden für das Companion-Objekt werden durch statische Methoden für die Klasse zugänglich gemacht. Dies wird bei Java-Klassen, für die Sie später einen "Companion" definieren, niemals der Fall sein.
Drexin
15

Ist es, wenn wir versuchen, nur Java-Objekte zu instanziieren?

Überhaupt nicht. Es gibt zwei allgemeine Fälle, in denen Sie newin Scala verzichten. Mit Singleton-Objekten (die häufig zum Speichern statischer Funktionen und als eine Art Factory verwendet werden, die der in Java gezeigten ähnelt):

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

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

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

Bei einer Fallklasse (tatsächlich gibt es darunter Klasse + Objekt = Begleitmuster , z. B. Klasse und Objekt mit demselben Namen):

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


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

Wenn Sie also mit einfachen Klassen arbeiten, sind die Regeln dieselben wie bei 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")

Bonus, es gibt eine anonyme Klasse in Scala, die so aufgebaut werden kann:

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
OM Nom Nom
quelle
1
Geht es dir gut, Kumpel?
Jacob B
0

Versuchen wir nur Java-Objekte zu instanziieren?

Mit Scala 3 (das Mitte 2020, acht Jahre später, veröffentlicht werden soll), basierend auf Dotty : Nie.

Scala 3 wird " new" fallen lassen, wie in diesem Thread

Mit Creator-Anwendungen können Sie mithilfe der einfachen Funktionsaufrufsyntax Instanzen einer Klasse erstellen, auch wenn keine Apply-Methode implementiert ist.

Beispiel:

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

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

Creator-Anwendungen verallgemeinern eine Funktionalität, die bisher nur für Fallklassen bereitgestellt wurde, aber der Mechanismus, wie dies erreicht wird, unterscheidet sich geringfügig.
Anstelle einer automatisch generierten Apply-Methode fügen wir einem Funktionsaufruf eine neue mögliche Interpretation hinzu f(args).

VonC
quelle