我不确定您是否真的需要所有这些,为什么不只是这样呢?
@annotation.implicitNotFound(msg = "${T} is not a valid Location type.")
sealed trait Location[T] {
def getPath(location: T, path: String): T
}
object Location {
final def apply[T](implicit location: Location[T]): Location[T] = location
implicit final val StringLocation: Location[String] =
new Location[String] {
override final def getPath(bucket: String, path: String): String =
s"fs://${bucket}/$path"
}
implicit final val StringListLocation: Location[List[String]] =
new Location[List[String]] {
override final def getPath(buckets: List[String], path: String): List[String] =
buckets.map(bucket => s"fs://${bucket}/$path")
}
}
final class Log[L : Location](location: L, path: String) {
def getPath(): L =
Location[L].getPath(location, path)
}
像这样工作:
new Log(location = "root", "foo/bar").getPath()
// val res: String = fs://root/foo/bar
new Log(location = List("base1", "base2"), "foo/bar").getPath()
// val res: List[String] = List(fs://base1/foo/bar, fs://base2/foo/bar)
new Log(location = 10, "foo/bar").getPath()
// Compile time error: Int is not a valid Location type.
如果你真的,真的,真的想拥有所有这些课程,你可以这样做:
sealed trait OneOrMany extends Product with Serializable
final case class One(path: String) extends OneOrMany
final case class Many(paths: List[String]) extends OneOrMany
sealed trait Location extends Product with Serializable {
type T <: OneOrMany
}
final case class OneLocation(bucket: String) extends Location {
override final type T = One
}
final case class ManyLocations(buckets: List[String]) extends Location {
override final type T = Many
}
@annotation.implicitNotFound(msg = "Not found a Path for Path {L}")
sealed trait Path[L <: Location] {
def getPath(location: L, path: String): L#T
}
object Path {
implicit final val OneLocationPath: Path[OneLocation] =
new Path[OneLocation] {
override final def getPath(location: OneLocation, path: String): One =
One(path = s"fs://${location.bucket}/$path")
}
implicit final val ManyLocationsPath: Path[ManyLocations] =
new Path[ManyLocations] {
override final def getPath(location: ManyLocations, path: String): Many =
Many(paths = location.buckets.map(bucket => s"fs://${bucket}/$path"))
}
}
final class Log[L <: Location](location: L, path: String) {
def getPath()(implicit ev: Path[L]): L#T =
ev.getPath(location, path)
}
哪个像你想要的那样工作:
val onePath: One = new Log(OneLocation("root"), "foo/bar").getPath()
// val onePath: One = One(fs://root/foo/bar)
val manyPath: Many = new Log(ManyLocations(List("base1", "base2")), "foo/bar").getPath()
// val manyPath: Many = Many(List(fs://base1/foo/bar, fs://base2/foo/bar)