如何在scala中通过类型参数的类型成员约束参数?

时间:2017-03-06 14:32:29

标签: scala generics types

函数reduceTo获取一个类型参数,指示应返回的时间序列的类型,但函数splitInto需要一个Period值。我想确保它们是连贯的,所以你不能这样做:

reduceTo[MonthlySeries](period=Weekly)  // not ok
reduceTo[MonthlySeries](period=Monthly) // but this is ok
reduceTo[MonthlySeries]  // even better, derive the period from the type param

类型参数应该足够但我似乎无法从参数化类型中获取我需要的Period信息。这是简化的代码:

sealed trait Period
case class Daily extends Period
case class Monthly extends Period


sealed abstract class TimeSeries {
    type T
}
case class DailySeries extends TimeSeries {
    type T = Daily.type
}
case class MonthlySeries extends TimeSeries {
    type T = Monthly.type
}

implicit class DailySeriesOps(lhs: DailySeries) {

    def reduceTo[G: TimeSeries](period: Period):G {
        // instead of sending the period in, how do I get
        // the period value from the type G?
        // Or at least constrain the period value?
        val s = splitInto(period, lhs)
        val reduced : G = ...
        // this is ugly
        assert(reduced.period == period, s"Reducing to $period but timeseries is ${reduced.period}")
    }
}

最初我认为路径依赖类型会有所帮助,比如

def reduceTo[G: TimeSeries](period: G.T)

但是根据我的理解,这将需要每日将在DailySeries中定义的类,因为它在其他环境中使用并不理想。

另一个不起作用的想法是不发送period参数但是从G获取值,但由于它的实例尚不存在,它不起作用

def reduceTo... = {
  val period = G.T
  ...
}

[更新]

也试过

def reduceTo[G : TimeSeries](period: TimeSeries#T: G = {
    val ts = reduce[F](period.asInstanceOf[GroupedPeriod], lhs)

但是这在reduceTo调用上的类型不匹配时无法编译:

type mismatch;
[error]  found   : com.example.metrics.Periods.Monthly.type
[error]  required: com.example.metrics.calculations.TimeSeries#T

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

根据您的评论,如果GroupedSeries有type T字段,您可以使用period: G#T,或者如果您不需要添加其他通用参数,请使用以下内容:

  def reduceTo[G <: GroupedSeries[_], T <: TimeSeries](period: T#T): G = {
    //Your code
  }

有了这个我的编译器说:

DailySeriesOps().reduceTo[DailySeries,DailySeries](Monthly) // I don't compile that
DailySeriesOps().reduceTo[DailySeries,DailySeries](Daily) // that i will
DailySeriesOps().reduceTo[MonthlySeries,MonthlySeries](Monthly) // that i will too
DailySeriesOps().reduceTo[MonthlySeries,MonthlySeries](Daily) // and not this one

但你的问题不容易再现,所以我不知道这是否可以回答你的问题,我希望有所帮助