为什么通用代数数据类型在成员类型上需要`T`?

Jus*_*mer 4 generics kotlin

我想定义一个通用代数数据类型,用于我的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> {
Run Code Online (Sandbox Code Playgroud)

但是,这是不允许的,因为这是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>()
}
Run Code Online (Sandbox Code Playgroud)

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

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

Result<T>.Success<T>(tv.someValue, pos)
Run Code Online (Sandbox Code Playgroud)

但这不会起作用而是我这样做:

Result.Success<T>(tv.someValue, pos)
Run Code Online (Sandbox Code Playgroud)

这对我来说是更好的语法,但我很难理解为什么我应该T在这里省略结果.

JB *_*zet 6

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

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

class Success(val value: String, val pos: Int) : Result<String>()
Run Code Online (Sandbox Code Playgroud)

另请注意,尽管结果和失败是通用的,但它们不会将任何通用类型用于通用类型.所以你实际上可以将你的类定义为

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

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

因为类的名称是Result.Success.参数类型不是类名的一部分.大多数情况下,没有必要指定它,因为它将被推断:

val r = Result.Success("foo", 1)
Run Code Online (Sandbox Code Playgroud)

创建一个实例Success<String>.如果您想要创建一个Success<CharSequence>,那么您必须明确指定泛型类型:

val r = Result.Success<CharSequence>("foo", 1)
Run Code Online (Sandbox Code Playgroud)

要么

val r: Result.Success<CharSequence> = Result.Success("foo", 1)
Run Code Online (Sandbox Code Playgroud)