web-dev-qa-db-fra.com

Les classes scellées dans une autre classe de Kotlin ne peuvent pas être compilées: impossible d'accéder à '<init>' car elles sont privées

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.

7

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:

Eh bien, il y a quelques détails d'implémentations non triviales (sur les constructeurs synthétiques de génération) qui ont été résolus pour les classes de niveau supérieur, mais comment le faire en général n'est pas clair.

5
Alexey Romanov

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
}
2
user8959091

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()
    }
}`
0
Abhay Agarwal