基于另一个类型参数的干扰类型参数
Interfering type parameter based on another type parameter
Kotlin 编译器是否可以根据另一个类型参数推断类型参数?
即:根据IntExample
class定义中的类型B推断类型A。
interface Something<A>
interface Example<A, B: Something<A>>
class IntSomething: Something<Int>
// Can Int type parameter be infered by the fact that IntSomething is Something<Int>?
// If yes, how could I specify B type parameter without specifing the infered A (Int) parameter?
class IntExample: Example<Int, IntSomething> // specifing Int here is painful!!!
想象一下,我们有更多这样的类型参数 - 如果可以(理论上)推断出其中的每一个,将会有很多样板来指定它们。
编辑
经过@KarstenGabriel 的详尽回复后,我将扩展前面的示例,以明确此处使用的类型参数的用途:
interface Something<A> {
val sth: A
}
interface Example<A, B: Something<A>> {
val eg: A
val something: B
}
data class IntSomething(override val sth: Int): Something<Int>
data class DescribedIntSomething(
override val sth: Int,
val description: String
): Something<Int>
data class DescribedIntExample(
override val eg: Int,
override val something: DescribedIntSomething,
): Example<Int, DescribedIntSomething> // specifing Int here is painful
fun main() {
val describedIntExample = DescribedIntExample(
eg = 1,
something = DescribedIntSomething(1, "Just one")
)
// We have to know that something is DescribedIntSomething to read description.
// Neither `*` nor `Something<Int>` is sufficient, we need `B: Something<Int>` to keep B
val description = describedIntExample.something.description
println(description)
}
所以我们使用类型参数 - A
和 B
作为 eg
和 something
的 return
值
- 不能使用通配符
*
,因为它只是表示 Any?
。我们需要保留具体类型 B
。 (例如,在示例中启用阅读说明)
- 不能使用通配符
Something<Int>
代替 B: Something<Int>
,原因与第 1 点相同
可能只是语言设计层面的问题。类型参数确实存在于编译时(它们稍后会被删除),所以 理论上 Example<DescribedIntSomething>
可能就足够了,而不是 Example<Int, DescribedIntSomething>
因为 DescribedIntSomething
是 Something<Int>
这个问题在某些假设下是可以解决的:
- 只有 属性
eg
(或其他类似情况)才需要类型参数 A
。
- 我们可以将
eg
转换为函数而不是 属性。
eg
(您的 A
值)的期望值可以从 something
的值(您的 B
值)导出。如果未推断值,则无法推断类型。
然后我们定义 Example
不带参数 A
:
interface Example<B: Something<*>> {
val something: B
}
现在在 Example
中我们不可能获得 B
的 Something
类型的类型参数,因为类型参数 A
在 Something<A>
在运行时不存在。所以你不能只询问 B
的实例它的 Something
类型参数是什么。而且 Kotlin 也不能这样做,因为如果您没有明确指定,信息就不会存在。
但是我们知道编译时的参数可以用在带有具体化参数的内联扩展函数中:
inline fun <reified A, reified B : Something<A>> Example<B>.eg(): A = something.sth
(文档:Inline functions with reified parameter and Extension functions)
在此示例中,我假设 eg
的值应为 sth
。
如果想让eg
是私有的,可以把函数放在Example
里面,然后设为私有,否则必须在class.[=35之外指定=]
现在你可以只定义你的子class而不需要指定以前的A
参数,但你仍然有正确的类型:
data class DescribedIntExample(
override val something: DescribedIntSomething,
) : Example<DescribedIntSomething>
fun main() {
val describedIntExample = DescribedIntExample(
something = DescribedIntSomething(1, "Just one")
)
val x = describedIntExample.eg() // x has inferred type Int and value 1
}
Kotlin 编译器是否可以根据另一个类型参数推断类型参数?
即:根据IntExample
class定义中的类型B推断类型A。
interface Something<A>
interface Example<A, B: Something<A>>
class IntSomething: Something<Int>
// Can Int type parameter be infered by the fact that IntSomething is Something<Int>?
// If yes, how could I specify B type parameter without specifing the infered A (Int) parameter?
class IntExample: Example<Int, IntSomething> // specifing Int here is painful!!!
想象一下,我们有更多这样的类型参数 - 如果可以(理论上)推断出其中的每一个,将会有很多样板来指定它们。
编辑
经过@KarstenGabriel 的详尽回复后,我将扩展前面的示例,以明确此处使用的类型参数的用途:
interface Something<A> {
val sth: A
}
interface Example<A, B: Something<A>> {
val eg: A
val something: B
}
data class IntSomething(override val sth: Int): Something<Int>
data class DescribedIntSomething(
override val sth: Int,
val description: String
): Something<Int>
data class DescribedIntExample(
override val eg: Int,
override val something: DescribedIntSomething,
): Example<Int, DescribedIntSomething> // specifing Int here is painful
fun main() {
val describedIntExample = DescribedIntExample(
eg = 1,
something = DescribedIntSomething(1, "Just one")
)
// We have to know that something is DescribedIntSomething to read description.
// Neither `*` nor `Something<Int>` is sufficient, we need `B: Something<Int>` to keep B
val description = describedIntExample.something.description
println(description)
}
所以我们使用类型参数 - A
和 B
作为 eg
和 something
return
值
- 不能使用通配符
*
,因为它只是表示Any?
。我们需要保留具体类型B
。 (例如,在示例中启用阅读说明) - 不能使用通配符
Something<Int>
代替B: Something<Int>
,原因与第 1 点相同
可能只是语言设计层面的问题。类型参数确实存在于编译时(它们稍后会被删除),所以 理论上 Example<DescribedIntSomething>
可能就足够了,而不是 Example<Int, DescribedIntSomething>
因为 DescribedIntSomething
是 Something<Int>
这个问题在某些假设下是可以解决的:
- 只有 属性
eg
(或其他类似情况)才需要类型参数A
。 - 我们可以将
eg
转换为函数而不是 属性。 eg
(您的A
值)的期望值可以从something
的值(您的B
值)导出。如果未推断值,则无法推断类型。
然后我们定义 Example
不带参数 A
:
interface Example<B: Something<*>> {
val something: B
}
现在在 Example
中我们不可能获得 B
的 Something
类型的类型参数,因为类型参数 A
在 Something<A>
在运行时不存在。所以你不能只询问 B
的实例它的 Something
类型参数是什么。而且 Kotlin 也不能这样做,因为如果您没有明确指定,信息就不会存在。
但是我们知道编译时的参数可以用在带有具体化参数的内联扩展函数中:
inline fun <reified A, reified B : Something<A>> Example<B>.eg(): A = something.sth
(文档:Inline functions with reified parameter and Extension functions)
在此示例中,我假设 eg
的值应为 sth
。
如果想让eg
是私有的,可以把函数放在Example
里面,然后设为私有,否则必须在class.[=35之外指定=]
现在你可以只定义你的子class而不需要指定以前的A
参数,但你仍然有正确的类型:
data class DescribedIntExample(
override val something: DescribedIntSomething,
) : Example<DescribedIntSomething>
fun main() {
val describedIntExample = DescribedIntExample(
something = DescribedIntSomething(1, "Just one")
)
val x = describedIntExample.eg() // x has inferred type Int and value 1
}