Scala / Shapeless:在案例类实例

时间:2017-06-21 12:48:02

标签: scala generics typeclass shapeless

我正在尝试创建一个类型类,它允许我增加一个名为&#34的Int字段; counter"在任何案例类中,只要该类具有这样的字段。

我试图用无形的方式做这件事,但是在击中墙壁之后(首先尝试消化"宇航员的无形指南""特征概述" of无形的2.0.0和Stack Overflow上的众多线程。

我想要的是能够做类似

的事情
case class MyModel(name:String, counter:Int) {}

val instance = MyModel("Joe", 4)
val incremented = instance.increment()
assert(incremented == MyModel("Joe", 5))

它适用于任何具有合适计数器字段的案例类。

我认为这可以使用类型类和Shapeless'记录抽象(以及一个隐式转换,以获取作为方法添加的增量功能)。裸骨将是这样的:

trait Incrementer[T] {
  def inc(t:T): T
}

object Incrementer {
  import shapeless._ ; import syntax.singleton._ ; import record._

  implicit def getIncrementer[T](implicit generator: LabelledGeneric[T]): Incrementer[T] = new Incrementer[T] {
    def inc(t:T) = {
      val repr = generator.to(t)
      generator.from(repr.replace('counter, repr.get('counter) + 1))
    }
  }     
}

但是,这不会编译。错误为value replace is not a member of generator.Repr。我想这是因为编译器没有任何保证T有一个名为counter的字段,它的类型为Int。但我怎么能这么说呢?关于Shapeless'是否有更好/更多的文档?记录?或者这是一种完全错误的方式?

2 个答案:

答案 0 :(得分:7)

您必须隐式要求Modifier

import shapeless._
import ops.record._
implicit class Incrementer[T, L <: HList](t: T)(
  implicit gen: LabelledGeneric.Aux[T, L],
  modifier: Modifier.Aux[L, Witness.`'counter`.T, Int, Int, L]
) {
  def increment(): T = gen.from(modifier(gen.to(t), _ + 1))
}

答案 1 :(得分:0)

您可以使用简单的类型派生来轻松完成:

<select multiple name="device[]" id="device" class="form-control" >
  <option value=\'ALL\' selected="selected">ALL</option>
  <option value=\'Android\'>Android</option>
  <option value=\'iPod\'>iPod</option>
  <option value=\'iPad\'>iPad</option>
  <option value=\'Java\'>Java</option>
  <option value=\'Windows\'>Windows</option>
  <option value=\'Linux\'>Linux</option>
  <option value=\'Mac\'>Mac</option>
</select>