无法编译 Kotlin 中另一个 class 中的密封 classes:无法访问 '<init>' 它是私有的

Sealed classes inside another class in Kotlin can't be compiled: cannot access '<init>' it is private

如果我使用 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()
}

编译不通过,报错:

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

但是,将它移到封闭的 class 之外使其编译:

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

为什么会这样?这是有意的行为吗?文档似乎没有提到这一点。

来自文档:

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
}

在 Kotlin 1.0 中,sealed 功能相当受限。为了 例如,所有的 subclasses 必须是嵌套的,而 subclass 不能变成 a data class(data classes 将在本章后面介绍)。 Kotlin 1.1 放松 限制并允许您在任何地方定义密封 classes 的子classes 同一个文件。 在给定的示例中,到目前为止是不允许的。可能在以后的发行版本中,他们会放宽此限制。 但是,您可以这样做:

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

是的,事实证明这是有意为之的行为。根据the proposal allowing non-nested subclasses:

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.