繁体   English   中英

如何避免在 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 是模式匹配的编译时替换。

为了在val中提供对它们的GetPaths权限,我必须将getSinglePath public 和path 如果您不想这样做,您可以将类型 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是零参数类型 class并且与磁铁模式略有相似。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM