如何避免在 Scala 中调用 asInstanceOf
How to avoid calling asInstanceOf in Scala
这是我的代码的简化版本。
我怎样才能避免调用 asInstanceOf
(因为这是一个设计不佳的解决方案的味道)?
sealed trait Location
final case class Single(bucket: String) extends Location
final case class Multi(buckets: Seq[String]) extends Location
@SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf"))
class Log[L <: Location](location: L, path: String) { // I prefer composition over inheritance
// I don't want to pass location to this method because it's a property of the object
// It's a separated function because there is another caller
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths(): Seq[String] =
location match {
case _: Single => Seq(this.asInstanceOf[Log[_ <: Single]].getSinglePath())
case m: Multi => m.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
试试类型class
class Log[L <: Location](location: L, val path: String) {
def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths[L]): Seq[String] = gp.getPaths(location, this)
}
trait GetPaths[L <: Location] {
def getPaths(location: L, log: Log[L]): Seq[String]
}
object GetPaths {
implicit val single: GetPaths[Single] = (_, log) => Seq(log.getSinglePath())
implicit val multi: GetPaths[Multi] = (m, log) => m.buckets.map(bucket => s"fs://${bucket}/${log.path}")
}
通常类型 class 是模式匹配的编译时替代。
我不得不将 getSinglePath
public 和 path
设为 val
以便在 GetPaths
中提供对它们的访问。如果你不想这样做,你可以将类型 class 嵌套到 Log
class Log[L <: Location](location: L, path: String) {
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths[L]): Seq[String] = gp.getPaths(location)
private trait GetPaths[L1 <: Location] {
def getPaths(location: L1): Seq[String]
}
private object GetPaths {
implicit def single(implicit ev: L <:< Single): GetPaths[L] = _ => Seq(getSinglePath())
implicit val multi: GetPaths[Multi] = _.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
实际上我们不必显式传递 location
也不需要 L1
class Log[L <: Location](location: L, path: String) {
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths): Seq[String] = gp.getPaths()
private trait GetPaths {
def getPaths(): Seq[String]
}
private object GetPaths {
implicit def single(implicit ev: L <:< Single): GetPaths = () => Seq(getSinglePath())
implicit def multi(implicit ev: L <:< Multi): GetPaths = () => location.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
现在GetPaths
是零参数type class and slightly similar to magnet pattern.
这是我的代码的简化版本。
我怎样才能避免调用 asInstanceOf
(因为这是一个设计不佳的解决方案的味道)?
sealed trait Location
final case class Single(bucket: String) extends Location
final case class Multi(buckets: Seq[String]) extends Location
@SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf"))
class Log[L <: Location](location: L, path: String) { // I prefer composition over inheritance
// I don't want to pass location to this method because it's a property of the object
// It's a separated function because there is another caller
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths(): Seq[String] =
location match {
case _: Single => Seq(this.asInstanceOf[Log[_ <: Single]].getSinglePath())
case m: Multi => m.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
试试类型class
class Log[L <: Location](location: L, val path: String) {
def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths[L]): Seq[String] = gp.getPaths(location, this)
}
trait GetPaths[L <: Location] {
def getPaths(location: L, log: Log[L]): Seq[String]
}
object GetPaths {
implicit val single: GetPaths[Single] = (_, log) => Seq(log.getSinglePath())
implicit val multi: GetPaths[Multi] = (m, log) => m.buckets.map(bucket => s"fs://${bucket}/${log.path}")
}
通常类型 class 是模式匹配的编译时替代。
我不得不将 getSinglePath
public 和 path
设为 val
以便在 GetPaths
中提供对它们的访问。如果你不想这样做,你可以将类型 class 嵌套到 Log
class Log[L <: Location](location: L, path: String) {
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths[L]): Seq[String] = gp.getPaths(location)
private trait GetPaths[L1 <: Location] {
def getPaths(location: L1): Seq[String]
}
private object GetPaths {
implicit def single(implicit ev: L <:< Single): GetPaths[L] = _ => Seq(getSinglePath())
implicit val multi: GetPaths[Multi] = _.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
实际上我们不必显式传递 location
也不需要 L1
class Log[L <: Location](location: L, path: String) {
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths): Seq[String] = gp.getPaths()
private trait GetPaths {
def getPaths(): Seq[String]
}
private object GetPaths {
implicit def single(implicit ev: L <:< Single): GetPaths = () => Seq(getSinglePath())
implicit def multi(implicit ev: L <:< Multi): GetPaths = () => location.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
现在GetPaths
是零参数type class and slightly similar to magnet pattern.