我想模拟每小时或每天的日志文件
sealed trait Level
case object Hour extends Level
case object Day extends Level
sealed trait Log[L <: Level]
我想要一个返回给定级别的所有日志的方法。所以这是签名
def byLevel[L <: Level](l: L) : Seq[Log[L]]
给出一些具体的日志实例(实际代码中还有很多):
case object HourlyLog extends Log[Hour.type]
case object DailyLog extends Log[Day.type]
我已经找到了以下实现:
object Log {
case class Pair[L <: Level](level : L, logs: Seq[Log[L]])
val logs = Seq(
Pair(Hour, Seq(HourlyLog)),
Pair(Day, Seq(DailyLog))
)
def byLevel[L <: Level](l: L) : Seq[Log[L]] = logs.find(_.level == l).get.logs.asInstanceOf[Seq[Log[L]]]
}
我的问题是:
.asInstanceOf
吗?Pair
包装吗?HMap
可以做到这一点)?答案 0 :(得分:1)
您似乎无论如何都要在随播对象上使用简单的对象比较,那么为什么要将它们与类型复杂化而不是将Hour
和Day
视为一个好的旧枚举?如果您想将Seq[DailyLog]
和Seq[HourlyLog]
存储在同一个列表中,则需要asInstanceOf
喜欢与否。
无论如何,您可以采取以下措施来摆脱Pair
和asInstanceOf
:
Hour
和Day
视为枚举值(仅限值,无类型)这三种方法都不使用Pair
,也不使用asInstanceOf
(一个使用Map
,但是......这就是你的Pair
正在做的事情。代码的三面墙中的每一面都可以自行编译。
只有值,没有类型,基本上是枚举
sealed trait Level
case object Hour extends Level
case object Day extends Level
sealed trait Log
case object HourlyLog extends Log
case object DailyLog extends Log
object Log {
val logs = Map[Level, Seq[Log]](
Hour -> Seq(HourlyLog, HourlyLog, HourlyLog, HourlyLog),
Day -> Seq(DailyLog)
)
def byLevel(l: Level): Seq[Log] = logs(l)
}
import Log._
println(byLevel(Hour))
println(byLevel(Day))
输出:
List(HourlyLog, HourlyLog, HourlyLog, HourlyLog)
List(DailyLog)
只有类型,没有对象值,暗示
sealed trait Level
sealed trait Hour extends Level
sealed trait Day extends Level
abstract class Log[L <: Level]
case object HourlyLog extends Log[Hour]
case object DailyLog extends Log[Day]
object Log {
case class Logs[L <: Level](val logs: Seq[Log[L]])
implicit val hourlyLogs = Logs[Hour](Seq(
HourlyLog, HourlyLog, HourlyLog, HourlyLog
))
implicit val dailyLogs = Logs[Day](Seq(
DailyLog
))
def byLevel[L <: Level](implicit logs: Logs[L]): Seq[Log[L]] =
logs.logs
}
import Log._
println(byLevel[Hour])
println(byLevel[Day])
输出:
List(HourlyLog, HourlyLog, HourlyLog, HourlyLog)
List(DailyLog)
混合方式,所有内容混合在一起
sealed trait Level
case object Hour extends Level
case object Day extends Level
sealed trait Log[L <: Level]
case object HourlyLog extends Log[Hour.type]
case object DailyLog extends Log[Day.type]
object Log {
case class Logs[L <: Level](val logs: Seq[Log[L]])
implicit val hourlyLogs = Logs[Hour.type](Seq(
HourlyLog, HourlyLog, HourlyLog, HourlyLog
))
implicit val dailyLogs = Logs[Day.type](Seq(
DailyLog
))
def byLevel[L <: Level](l: L)(implicit logs: Logs[L]): Seq[Log[L]] =
logs.logs
}
import Log._
println(byLevel(Hour))
println(byLevel(Day))
输出:
List(HourlyLog, HourlyLog, HourlyLog, HourlyLog)
List(DailyLog)
答案 1 :(得分:0)
根据具体情况,有不同的摆脱铸造的方法。
如果您希望将Log[Hour]
视为Log[Level]
的特殊情况(因此,每次您需要Log [Level]时,您可以使用Log[Hour]
替换它)使用协方差:{ {1}}
您需要它才能将[+L <: Level]
视为HourlyLog
(Log
)的子类型
当您遇到可能混合的子类型集合的情况时,您可以使用collect:
sealed trait Log[+L <: Level]
嗯,你仍然需要注释日志的类型,但它更干净,并且不要求你使用无形而不是任何其他魔法。
至于摆脱Pair包装器 - 在JVM上你会有一个类型擦除。您需要与运行时检查的内容进行比较。我可以想到像def byLevel[L <: Level](l: L): Seq[Log[L]] = logs.collect { case Pair(l2, logs: Seq[Log[L]]) if l2 == l => logs }.flatten
或ClassTag
这样的东西......但你仍然需要将它存储在某个地方(例如作为隐式构造函数参数TypeTag
),然后与之进行比较。所以我确定它是,但它会产生一些样板。
或者您可以使用sealed trait Log[+L <: Level: ClassTag]
进行过滤/收集,但是您必须在某个地方明确地存储它以将HourlyLog
映射到Hour
过滤...我不确定值得努力。可能如果你在常规基础上进行,那么推出专用类型类并提供暗示是值得的......但这是你的号召。根据您的使用情况,可能是过度工程和纯度为了纯度...或保持代码库可维护的东西。在我谦卑的经历中,有时候&#34;脏&#34;解决方案做得很好。