为什么泛型代数数据类型在成员类型上需要`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>() } 

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

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

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

但是,这不会工作,而是我这样做:

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

这对我来说是最好的语法,但是我正在努力去理解为什么我应该在这里忽略结果。

Result是一个泛型类,具有一个名为T的单一通用参数。类名是Result但不是Result<T>

Success也是一个通用的课程。 所以,因为它是通用的,所以你需要把它定义为Success<T> 。 如果你不这样做,那么它不是通用的了。 请注意,即使它是通用结果的子类,它也可能是非泛型类型。 例如:

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

在你的例子中有三个不同的通用参数,而不是一个。 即你的代码相当于:

 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参数,所以最好省略。

它应该工作,如果你使用这样的方差,

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