为什么泛型代数数据类型要求在成员类型上使用' T '



我想定义一个通用代数数据类型用于我的parse函数,像这样:

sealed class Result<T> {
    class Success(val value: T, val pos: Int) : Result<T>()
    class Failure(val message: String, val pos: Int) : Result<T>()
}
fun <T> parse(t: Parser<T>, input: String, initialPos: Int = 0, collectErrors: Boolean = true) : Result<T> {

但是这是不允许的,因为T是一个未定义的引用。

如果我添加T到所有的成员类型,它工作:

sealed class Result<T> {
    class Success<T>(val value: T, val pos: Int) : Result<T>()
    class Failure<T>(val message: String, val pos: Int) : Result<T>()
}

对我来说,这有点令人困惑,这让我相信我在这里错过了一些东西。为什么在第一种情况下定义成员类型时看不到T ?

另外,当创建Success的实例时,我希望语法是:

Result<T>.Success<T>(tv.someValue, pos)

但是这不起作用,我这样做:

Result.Success<T>(tv.someValue, pos)

这对我来说是更可取的语法,但我很难理解为什么我应该在这里留下T的结果

Result是一个泛型类,有一个单一的泛型参数t,但类名是Result,而不是Result<T>

Success也是一个泛型类。因此,由于它是通用的,您需要将其定义为Success<T>。如果你不这样做,那么它就不再是通用的了。注意,即使它是泛型Result的子类,它也可以是非泛型类型。例如:

class Success(val value: String, val pos: Int) : Result<String>()

还要注意,尽管Result和Failure是泛型的,但它们不使用泛型类型做任何事情。所以你可以将类定义为

sealed class Result {
    class Success<T>(val value: T, val pos: Int) : Result()
    class Failure(val message: String, val pos: Int) : Result()
}

现在,为什么你需要使用Result.Success<T>(tv.someValue, pos)而不是Result<T>.Success<T>(tv.someValue, pos) ?

因为类的名称是Result.Success。参数类型不是类名的一部分。大多数情况下,根本不需要指定它,因为它会被推断出来:

val r = Result.Success("foo", 1)

创建Success<String>实例。如果您想创建一个Success<CharSequence>,那么您必须显式指定泛型类型:

val r = Result.Success<CharSequence>("foo", 1)

val r: Result.Success<CharSequence> = Result.Success("foo", 1)

规则与Java中的相同。它基本上归结为SuccessFailureResult的静态嵌套类。Kotlin中没有"成员类型",静态嵌套类是可以访问外部类作用域的常规类。如果一个类继承了泛型超类,它总是需要绑定泛型类型参数。

相反,非静态嵌套类(由inner关键字表示)总是携带外部类的泛型类型参数。这样就可以构造以下类型层次结构:

open class Foo<T> {
    inner class Bar : Foo<T>()
}

要实例化Bar,你需要有一个Foo的实例:

val b = Foo<String>().Bar()

如果你像这样使用out方差,它应该可以工作,

sealed class Result<out T> {
  data class Success<out T>(val value: T, val pos: Int) : Result<T>()
  data class Failure(val message: String, val pos: Int) : Result<Nothing>()
}

在您的示例中,有三个不同的通用参数,而不是一个。也就是说,你的代码相当于:

sealed class Result<I> {
    class Success<A>(val value: A, val pos: Int) : Result<A>()
    class Failure<B>(val message: String, val pos: Int) : Result<B>()
}

但是其他答案提到,你没有使用IB参数,所以它们最好被省略

最新更新