Запечатанные классы внутри другого класса в Kotlin не могут быть скомпилированы: нет доступа к '<init>', это частный

Если бы я использовал пример из документы,

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()
}

он не компилируется с ошибкой:

Cannot access '<init>', it is private in 'Expr'.

Однако перемещение его за пределы включающего класса заставляет его компилироваться:

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() {
}

Почему это так? Это запланированное поведение? Документы, похоже, не упоминают об этом.

Думаю, это просто ограничение компилятора. С технической точки зрения я не понимаю, почему закрытые классы не могут быть вложенными.

Maxim 27.06.2018 10:31

Для меня это больше похоже на ошибку, чем на ограничение. Если это по какой-то причине предназначено, по крайней мере, сообщение должно быть исправлено.

Alexey Romanov 27.06.2018 11:34

В конце концов, это не ошибка.

Alexey Romanov 14.07.2018 14:35
Сила классов Java: сравнение с языком C
Сила классов Java: сравнение с языком C
Абстракция" - это процесс упрощения сложных сущностей или концепций реального мира с целью их применения в форме программирования. В Java класс...
19
3
8 155
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Из документации:

A sealed class is abstract by itself, it cannot be instantiated directly and can have abstract members.

Sealed classes are not allowed to have non-private constructors (their constructors are private by default).

Я предполагаю, что вам следует использовать этот пример:

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
}

Интересно, как этот Const(...) : Expr() работает, если не разрешены не частные конструкторы.

Maxim 27.06.2018 10:28

Здесь вы используете конструктор Const. Ограничение не распространяется на классы, расширяющие закрытые классы.

user8959091 27.06.2018 10:33

Ага. Для закрытых классов верхнего уровня компилятор создает общедоступный конструктор, который используется внутри, а для вложенных - нет.

Maxim 27.06.2018 10:40

@Maxim Подожди, публика? Не защищен?

Alexey Romanov 15.07.2018 14:46

В Kotlin 1.0 закрытая функциональность довольно ограничена. Для Например, все подклассы должны быть вложенными, и подкласс не может быть класс данных (классы данных рассматриваются далее в этой главе). Kotlin 1.1 расслабляет ограничения и позволяет вам определять подклассы запечатанных классов в любом месте тот же файл. В данном примере это не разрешено до сих пор. Возможно, в более поздних версиях выпуска это ограничение будет ослаблено. Однако вы можете сделать это:

`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()
    }
}`
Ответ принят как подходящий

Да, это предполагаемое поведение. Согласно предложение, разрешающее не вложенные подклассы:

Proposal: allow top-level subclasses for a top-level sealed class in the same file.

For a non top-level sealed class all subclasses should be declared inside it. So, for such classes nothing changes.

Нужный сценарий указан как открытый вопрос. Билет на него есть по адресу https://youtrack.jetbrains.com/issue/KT-13495. Похоже, что сейчас над этим никто не работает. При обсуждении предложения разработчик говорит:

Well, there is some not-trivial implementations details(about generation synthetic constructors) which was solved for top-level classes but how do it in general is not clear.

Другие вопросы по теме