Si j’ai utilisé l’exemple tiré de docs ,
class SomeActivity : AppCompatActivity() {
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
il ne compile pas, avec l'erreur:
Cannot access '<init>', it is private in 'Expr'.
Cependant, le déplacer en dehors de la classe englobante le compile:
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
class SomeActivity : AppCompatActivity() {
}
Pourquoi cela est-il ainsi? Est-ce un comportement prévu? La documentation ne semble pas en parler.
Oui, il s’agit d’un comportement voulu. Selon la proposition autorisant les sous-classes non imbriquées :
Proposition: autoriser les sous-classes de niveau supérieur pour une classe scellée de niveau supérieur dans le même fichier.
Pour une classe scellée de niveau supérieur, toutes les sous-classes doivent y être déclarées. Donc, pour de telles classes, rien ne change.
Le scénario que vous souhaitez apparaît comme une question ouverte. Il existe un ticket pour cela à https://youtrack.jetbrains.com/issue/KT-13495 . Personne ne semble y travailler pour le moment. Dans la discussion de la proposition, le développeur dit:
De la documentation:
Une classe scellée est abstraite par elle-même, elle ne peut pas être instanciée directement et peut avoir des membres abstraits.
Les classes scellées ne sont pas autorisées à avoir des constructeurs non privés (leurs constructeurs Sont privés par défaut).
Je suppose que la façon dont vous devriez utiliser l'exemple est la suivante:
fun main(args: Array<String>) {
val c = Const(5.0)
val s = Sum(Const(1.0), Const(3.0))
println(eval(c))
println(eval(s))
}
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// the `else` clause is not required because we've covered all the cases
}
Dans Kotlin 1.0, la fonctionnalité scellée est plutôt restreinte. Par exemple, toutes les sous-classes doivent être imbriquées et une sous-classe ne peut pas être transformée en classedata (les classes de données sont traitées plus loin dans ce chapitre). Kotlin 1.1 assouplit Les restrictions et vous permet de définir des sous-classes de classes scellées n'importe où dans Le même fichier . Dans l'exemple donné, cela n'est pas autorisé jusqu'à présent. Peut-être, dans les versions ultérieures, ils vont assouplir cette restriction. Cependant, vous pouvez faire ceci:
`class SomeActivity {
sealed class Expr {
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
}`