我想定义一个通用代数数据类型用于我的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中的相同。它基本上归结为Success
和Failure
是Result
的静态嵌套类。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>()
}
但是其他答案提到,你没有使用I
和B
参数,所以它们最好被省略