Почему универсальные типы алгебраических данных требуют `T` для типов членов?

Я хочу определить Generic Algebraic Data Type для использования с моей функцией 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 здесь.

Result – это общий класс с одним общим параметром с именем T. Имя класса – это Result но не Result<T> .

Success – тоже общий класс. Итак, поскольку он является общим, вам нужно определить его как Success<T> . Если вы этого не сделаете, то это уже не общее. Обратите внимание, что, хотя это подкласс Result, который является общим, он может быть не общим типом. Например:

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

Также обратите внимание, что хотя результат и отказ являются общими, они не используют свой общий тип для чего-либо. Таким образом, вы могли бы определить свои классы как

 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 and Failure являются статическими вложенными классами Result . В 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>() } 

Но как упоминаются другие ответы, вы не используете параметры I и B , поэтому их лучше исключить.

Он должен работать, если вы используете дисперсию 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>() }