generics - 针对F <out X>的特定情况F <Nothing>缺少HKT的解决方法

标签 generics kotlin types higher-kinded-types

在以下最小示例中,Kotlin中是否有任何方法可以通过将Foo保留为抽象来将BardefaultBar分开?

sealed class Bar<out X> {
  data class Hello<X>(val who: X): Bar<X>()
  object Empty : Bar<Nothing>()
}

interface Foo {
  fun defaultBar(): Bar<Nothing> = Bar.Empty
  fun <P> foo(bar: Bar<P> = defaultBar()): Bar<P> = bar
}

fun main(args: Array<String>) {
  println((object : Foo{}).foo(Bar.Hello("world")))
}
所谓“分开”,是指我希望FooBar放在两个完全独立的文件中,因此它们不要互相提及。方法foo应该是“硬”的,应该保留在Foo中。 defaultBar方法应该是“简单的”,可以在任何地方实现。我想同时提及FooBar的唯一地方应该是一些单独的类,该类提供defaultBar的具体实现。

我尝试过的
在最初的几分钟中,以下尝试似乎很有希望:
sealed class Bar<out X> {
  data class Hello<X>(val who: X): Bar<X>()
  object Empty : Bar<Nothing>()
}

interface Foo<B>{
  fun <P: B> defaultB(): P
  fun <P: B> foo(bar: P = defaultB()): P = bar
}

object FooImpl : Foo<Bar<Any>> {
  override fun <P: Bar<Any>> defaultB(): P = Bar.Empty
}

fun main(args: Array<String>) {
  println(FooImpl.foo(Bar.Hello("world")))
}
不幸的是,Kotlin无法从Bar<out X>P subtypeOf Bar<Any>Bar<Nothing> subtypeOf P派生。
此外,我也不能写类似
sealed class Bar<out X> {
  data class Hello<X>(val who: X): Bar<X>()
  object Empty : Bar<Nothing>()
}

interface Foo<B, N: B> {
  fun defaultBar(): N
  fun <P : B super N> foo(bar: Bar<P> = defaultBar()): Bar<P> = bar
}

object FooImpl : Foo<Bar<Any>, Bar<Nothing>> {
  fun defaultBar(): Bar<Nothing> = Bar.Empty
}

fun main(args: Array<String>) {
  println(FooImpl.foo(Bar.Hello("world")))
}
,因为除了不支持HKT外,Kotlin还不支持使用现场的下限字体。

(可选)我希望有可能
以下Scala片段显示了我的意思:
sealed trait Bar[+X]
case class Hello(who: String) extends Bar[String]
case object Empty extends Bar[Nothing]

trait Foo {
  val defaultBar: Bar[Nothing] = Empty
  def foo[P](bar: Bar[P] = defaultBar): Bar[P] = bar
}

println((new Foo{}).foo(Hello("world")))
可以重构为:
import language.higherKinds

sealed trait Bar[+X]
case class Hello(who: String) extends Bar[String]
case object Empty extends Bar[Nothing]

trait Foo[B[+_]] {
  val defaultB: B[Nothing]
  def foo[P](b: B[P] = defaultB): B[P] = b
}

object FooImpl extends Foo[Bar] {
  val defaultB: Bar[Nothing] = Empty
}

println(FooImpl.foo(Hello("world")))
因此Foo在任何地方都不会提及Bar

(可选)为什么我希望有可能
在这种特殊情况下,不需要完整的HKT,因为我们只需要对Bar类型的Nothing求值:
sealed trait Bar[+X]
case class Hello(who: String) extends Bar[String]
case object Empty extends Bar[Nothing]

trait Foo[N] {
  val defaultBar: N
  def foo[P >: N](bar: P = defaultBar): P = bar
}

object FooInstance extends Foo[Bar[Nothing]] {
  val defaultBar = Empty
}

println(FooInstance.foo(Hello("world")))
如果没有更高的种类,这可以工作,Java的super就足够了。但是,如上所述,Kotlin在使用站点似乎没有>: / super /下限类型。


除了将foo移至FooImpl之外(即将FooFooImpl合并到一个大文件中),还有什么可以做的?

最佳答案

您可以通过使super扩展功能并编写foo而不是B : P来模仿P super B:

sealed class Bar<out X> {
    data class Hello<out X>(val who: X) : Bar<X>()
    object Empty : Bar<Nothing>()
}

interface Foo<out B> {
    fun defaultBar(): B
}

fun <B : P, P> Foo<B>.foo(bar: P = defaultBar()): P = bar

object FooImpl : Foo<Bar<Nothing>> {
    override fun defaultBar(): Bar<Nothing> = Bar.Empty
}

fun main() {
    println(FooImpl.foo(Bar.Hello("world")))
}

关于generics - 针对F <out X>的特定情况F <Nothing>缺少HKT的解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59056049/

相关文章:

angularjs - Angular post json来表达

c# - EF - 无法将运算符 '==' 应用于类型为 'TId' 和 'TId' 的操作数

android - 非空字段在 Glide 中为空

kotlin - 为什么 'is' 关键字仅适用于 kotlin 中的开放类?

android - 如何查看变化的集合?

sql - 复合类型数组上的 SUM 和 GROUP BY

在 Haskell 中对抽象数据类型进行排序

java - 找到原始类型,缺少泛型类的返回参数

c# - 我能否根据用于该类的泛型类型是值类型还是引用类型,从泛型类中的函数返回不同的类型?

c# - 没有唯一键的字典