具有 ADT 和 Aux 模式的类型安全
Type-safety with ADT and Aux pattern
我正在使用 ADT 和 Aux 模式设计类型安全代码,无法摆脱一些 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 <: Source: ClassTag
,但是这里好像用处不大。也许其他反射技巧?
请看解释为什么签名
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")
)
}
}
不起作用,有几种解决方法:
例如尝试输入 class
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)
我正在使用 ADT 和 Aux 模式设计类型安全代码,无法摆脱一些 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 <: Source: ClassTag
,但是这里好像用处不大。也许其他反射技巧?
请看解释为什么签名
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")
)
}
}
不起作用,有几种解决方法:
例如尝试输入 class
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)