带泛型的Kotlin密封接口为何无法为子类型推断约束?
问题原因与解决方法
报错原因
你写的代码里,processFoo的泛型参数T是无界的,再加上Foo是协变的(out T),这就导致Bar<K>(K是List<Int>的子类型)可以被当作Foo<Any>传入processFoo。
当进入is Bar分支时,编译器只能推断出foo.value是T的子类型(因为Foo<out T>的value是T,而Bar<K>的value是K,且K是T的子类型),但T可以是任意类型(比如Any),编译器无法确定这个value是Iterable的实例,自然找不到合适的forEach方法,所以报错。
解决方法
方法1:给
processFoo的泛型T加上约束
明确T是Iterable的子类型,让编译器直接识别value具备forEach方法:fun <T: Iterable<*>> processFoo(foo: Foo<T>) { when (foo) { is Bar -> foo.value.forEach(::println) } }方法2:在分支里显式指定
Bar的星号投影
把foo的类型细化为Bar<*>,编译器就能识别value是List<Int>的子类型(属于Iterable):fun <T> processFoo(foo: Foo<T>) { when (foo) { is Bar<*> -> foo.value.forEach(::println) } }方法3:安全类型转换(仅在确定类型时使用)
由于Bar的K约束为List<Int>的子类型,可直接将value强制转换为List<Int>:fun <T> processFoo(foo: Foo<T>) { when (foo) { is Bar -> (foo.value as List<Int>).forEach(::println) } }
内容的提问来源于stack exchange,提问作者Aiono
相关产品推荐
相关产品推荐

