我想实现一个基于类型的id生成器,我可以这样调用:
val nextPersonId = idGen.id[Person]
我希望IdGen成为一种特质(如果可能的话):
trait IdGen[L <: HList] {
def id[T] = {
if (T is an element in the L type) return 0L + number of previous calls for this T
else throw new RuntimeException("no such T in L")
}
}
class MyDao extends IdGen[Person :: Booking :: Charges :: HNil] {
//something needed here?
}
如何使用Shapeless实现这一目标?
我尝试过使用scala反射typeTag并迭代toString结果,但它很难看。
答案 0 :(得分:0)
好的,这是基于字符串的版本,它可能有许多关于大量案例的错误,并且要求实现者以提供隐式TypeTag的形式生成样板:
import shapeless._
import scala.collection.mutable
import scala.reflect.runtime.universe._
trait IdGen[L <: HList] {
implicit val ltag: TypeTag[L]
private val idGens = mutable.Map(typeTag[L].toString.split("""::\[""").toList.tail.map(_.split(""",shapeless""")(0) -> 0L): _*)
def id[T: TypeTag] = {
val t = typeOf[T].toString
val id = idGens(t)
idGens(t) = id + 1L
id
}
}
简单测试类:
import java.util.NoSuchElementException
import org.junit.{Assert, Test}
import shapeless._
import reflect.runtime.universe._
class Person
class Booking
class Charge
class MyDao(implicit val ltag: TypeTag[Person :: Booking :: HNil]) extends IdGen[Person :: Booking :: HNil]
class Testy {
val myDao = new MyDao
@Test(expected = classOf[NoSuchElementException])
def test {
Assert.assertEquals(0L, myDao.id[Person])
Assert.assertEquals(1L, myDao.id[Person])
Assert.assertEquals(0L, myDao.id[Booking])
myDao.id[Charge]
}
}
看到更好的实施将是非常有趣的。