Scala3中函数可接受超类型?List.fill类型标注存疑
代码与现象
示例代码:
val times4 = List.fill(4) val oranges = times4("orange") println(oranges)
运行输出:
List(orange, orange, orange, orange)
IntelliJ显示times4的类型为:
Nothing => List[Nothing]
问题解答
- 行为是否正确?
完全正确。这是Scala3类型推导、泛型协变与类型参数特化共同作用的结果。
List.fill(n)的签名是def fill[A](n: Int)(elem: A): List[A],当仅传入第一个参数4时,得到的是一个部分应用函数。此时Scala3会先将泛型参数A临时推断为Nothing(Scala类型系统的底部类型),但这只是编辑器未看到后续调用时的中间推断结果。
当调用times4("orange")时,Scala会对这个部分应用函数进行类型特化,将泛型参数A重新推断为String。由于Nothing是所有类型的子类型,结合函数类型的协变/逆变特性,Nothing => List[Nothing]会被自动适配为String => List[String],因此可以正常接收String参数。
- 函数是否可接受超类型?
这里的本质并非函数直接接受超类型,而是Scala的类型系统会在函数调用时重新解析泛型参数,修正初始的类型推断结果。
List.fill(4)返回的实际是一个泛型函数,可理解为[A] => A => List[A](Scala3的上下文泛型推导会自动处理这种延迟的类型绑定)。编辑器显示的Nothing => List[Nothing]只是未看到后续调用时的临时类型,当传入String参数后,泛型参数A被确定为String,函数实际类型就变为String => List[String],自然可以接收String参数。
总结:该行为是Scala3泛型系统的正常表现,编辑器的类型显示为中间状态,实际运行时的类型推断会根据调用场景完成正确绑定。
内容的提问来源于stack exchange,提问作者Mandroid

