Was ist ein versiegeltes Merkmal?

332

Versiegelte Klassen werden in 'Programmieren in Scala' beschrieben, versiegelte Merkmale jedoch nicht. Wo finde ich weitere Informationen zu einem versiegelten Merkmal?

Ich würde gerne wissen, ob ein versiegeltes Merkmal mit einer versiegelten Klasse identisch ist. Oder wenn nicht, was sind die Unterschiede? Wann ist es eine gute Idee, ein versiegeltes Merkmal zu verwenden (und wann nicht)?

John Threepwood
quelle

Antworten:

472

Ein sealedMerkmal kann nur in derselben Datei wie seine Deklaration erweitert werden.

Sie werden oft verwendet, um eine Alternative zu bieten enums . Da sie nur in einer einzigen Datei erweitert werden können, kennt der Compiler alle möglichen Untertypen und kann darüber nachdenken.

Zum Beispiel mit der Erklärung:

sealed trait Answer
case object Yes extends Answer
case object No extends Answer

Der Compiler gibt eine Warnung aus, wenn eine Übereinstimmung nicht vollständig ist:

scala> val x: Answer = Yes
x: Answer = Yes

scala> x match {
     |   case No => println("No")
     | }
<console>:12: warning: match is not exhaustive!
missing combination            Yes

Sie sollten also versiegelte Merkmale (oder versiegelte abstrakte Klassen) verwenden, wenn die Anzahl der möglichen Untertypen endlich und im Voraus bekannt ist. Weitere Beispiele finden Sie in den Implementierungen von Listen und Optionen .

paradigmatisch
quelle
112
Ich habe sechs Monate gebraucht, um zufällig hier anzukommen und zu verstehen, wie man Java Enum in Scala ersetzt.
sscarduzio
Sehr schön ! und nicht nur endlich und im Voraus bekannt, sondern auch Teil eines eingeschränkten (versiegelten?) Kontexts, in dem es sinnvoll ist, alle möglichen Untertypen wie yes | zu überprüfen nein, sogar | ungerade etc ...
Mário de Sá Vera
90

Ein versiegeltes Merkmal ist dasselbe wie eine versiegelte Klasse?

Soweit sealedja. Sie teilen natürlich die normalen Unterschiede zwischen traitund class.

Oder wenn nicht, was sind die Unterschiede?

Moot.

Wann ist es eine gute Idee, ein versiegeltes Merkmal zu verwenden (und wann nicht)?

Wenn Sie eine haben sealed class X, müssen Sie nach XUnterklassen suchen. Das gleiche gilt nicht für sealed abstract class Xoder sealed trait X. Sie könnten es also tun sealed abstract class X, aber das ist viel ausführlicher als nur traitund für wenig Vorteil.

Der Hauptvorteil der Verwendung von a abstract classüber a traitbesteht darin, dass Parameter empfangen werden können. Dieser Vorteil ist besonders relevant bei der Verwendung von Typklassen. Angenommen, Sie möchten beispielsweise einen sortierten Baum erstellen. Sie können dies schreiben:

sealed abstract class Tree[T : Ordering]

aber du kannst das nicht tun:

sealed trait Tree[T : Ordering]

da Kontextgrenzen (und Ansichtsgrenzen) mit impliziten Parametern implementiert werden. Da Merkmale keine Parameter empfangen können, können Sie dies nicht tun.

Persönlich bevorzuge sealed traitund benutze ich es , es sei denn, ein bestimmter Grund zwingt mich dazu, a zu verwenden sealed abstract class. Und ich spreche nicht über subtile Gründe, sondern über Gründe, die Sie nicht ignorieren können, z. B. die Verwendung von Typklassen.

Daniel C. Sobral
quelle
"Da Kontextgrenzen (und Ansichtsgrenzen) mit impliziten Parametern implementiert werden." - Könnten Sie das näher erläutern?
Ruby
@Ruby - ziemlich späte Antwort, aber falls Sie oder jemand anderes interessiert ist: context bounding ( [A: F]) funktioniert nicht so wie Varianzbeschränkungen. Vielmehr ist es syntaktischer Zucker, der einen impliziten F[A]Umfang erfordert . Es wird im Allgemeinen verwendet, um Instanzen von Typklassen auf eine Weise zu beschwören, die etwas knapper und leichter zu lesen ist als ein impliziter Parameter ( (implicit fa: F[A])), aber es funktioniert unter der Haube immer noch genauso, und wie Daniel betont, können Merkmale nicht funktionieren Das.
Mirichan
54

Aus dem Daily-Scala-Blog :

Wenn ein Merkmal "versiegelt" wird, werden alle seine Unterklassen in derselben Datei deklariert, und dies macht die Menge der Unterklassen endlich, was bestimmte Compilerprüfungen ermöglicht.

Brian Agnew
quelle
Vielen Dank. Mit "all seinen Unterklassen" bedeutet es Klassen und Eigenschaften?
John Threepwood
@ John - Ich habe es nicht versucht, aber ich vermute Klassen. Der Punkt beim Versiegeln ist, dass alles innerhalb dieser einen Quelleneinheit definiert ist
Brian Agnew
1
@ JohnThreepwood: Klassen, Eigenschaften und Objekte. In Scala wird der Begriff "Klasse" meistens für Klassen, Merkmale und Objekte verwendet. Nur wenn über die spezifischen Unterschiede zwischen ihnen gesprochen wird, bedeutet dies nur Klassen. Das SLS verwendet den Begriff "Vorlage", um sich sowohl auf Klassen als auch auf Merkmale zu beziehen. Dieser Begriff wird jedoch außerhalb des SLS nicht häufig verwendet, und es gibt keinen Begriff, der alle drei Klassen, Merkmale und Objekte umfasst.
Jörg W Mittag
30

Ich habe auch das Bedürfnis, Sie auf die Spezifikationen hinzuweisen:

Der versiegelte Modifikator gilt für Klassendefinitionen. Eine versiegelte Klasse darf nicht direkt vererbt werden, es sei denn, die vererbende Vorlage ist in derselben Quelldatei wie die geerbte Klasse definiert. Unterklassen einer versiegelten Klasse können jedoch überall vererbt werden.

- M. Odersky. Die Scala-Sprachspezifikation, Version 2.8. online, Sept. 2013.

BEIM
quelle
7

kurz:

  • Versiegelte Merkmale können nur in derselben Datei erweitert werden
  • Mit dieser Liste kann der Compiler alle möglichen Untertypen leicht erkennen
  • Verwenden Sie versiegelte Merkmale, wenn die Anzahl der möglichen Subtypen endlich und im Voraus bekannt ist
  • Eine Möglichkeit, so etwas wie Enum in Java zu erstellen
  • Hilfe beim Definieren algebraischer Datentypen (ADTs)

und für weitere Details Alles über versiegelte Merkmale in Scala

Majid Hosseini
quelle