【问题标题】:Type-safety with ADT and Aux patternADT 和 Aux 模式的类型安全
【发布时间】:2020-10-21 15:53:26
【问题描述】:

我正在使用 ADT 和 Aux-pattern 设计类型安全代码,并且无法摆脱一些 asInstanceOf。示例如下:

  sealed trait Source
  case object FileSystem extends Source
  case object Network extends Source

  sealed trait Data {
    type S <: Source
  }
  object Data {
    type Aux[T <: Source] = Data { type S = T }
  }
  case class RegularFile(path: String) extends Data { type S = FileSystem.type }
  case class Directory(path: String) extends Data { type S = FileSystem.type }
  case class UnixDevice(path: String) extends Data { type S = FileSystem.type }
  case class Remote(ip: String) extends Data { type S = Network.type }

  //Lots of asInstanceOf
  def availableData[S <: Source](src: Source): List[Data.Aux[S]] = {
    src match {
      case FileSystem => List(
        RegularFile("/tmp/test").asInstanceOf[Data.Aux[S]],
        Directory("/home/somename").asInstanceOf[Data.Aux[S]],
        UnixDevice("/dev/null").asInstanceOf[Data.Aux[S]],
      )
      case Network => List(
        Remote("192.168.0.1").asInstanceOf[Data.Aux[S]]
      )
    }
  }

在这种情况下,很明显asInstanceOf 是正确的,但是有没有办法得到它?

我正在考虑S &lt;: Source: ClassTag,但它在这里似乎没有用。也许其他反射技巧?

【问题讨论】:

标签: scala type-safety algebraic-data-types


【解决方案1】:

请看解释为什么签名

def availableData[S <: Source](src: S): List[Data.Aux[S]] = {
  src match {
    case FileSystem => List(
      RegularFile("/tmp/test"),
      Directory("/home/somename"),
      UnixDevice("/dev/null"),
    )
    case Network => List(
      Remote("192.168.0.1")
    )
  }
}

不起作用以及如何解决它的几种方法:

Generic function where the return type depends on the input type in Scala?

Why can't I return a concrete subtype of A if a generic subtype of A is declared as return parameter?

Type mismatch on abstract type used in pattern matching

例如尝试一个类型类

trait AvailableData[S <: Source] {
  def availableData(src: S): List[Data.Aux[S]]
}
object AvailableData {
  implicit val fileSystem: AvailableData[FileSystem.type] = _ =>
    List[Data.Aux[FileSystem.type]](
      RegularFile("/tmp/test"),
      Directory("/home/somename"),
      UnixDevice("/dev/null"),
    )
  implicit val network: AvailableData[Network.type] = _ =>
    List[Data.Aux[Network.type]](
      Remote("192.168.0.1")
    )
}

def availableData[S <: Source](src: S)(implicit 
  ad: AvailableData[S]
): List[Data.Aux[S]] = ad.availableData(src)

【讨论】:

    猜你喜欢
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多