2016-04-17 5 views
0

Ich möchte eine Art Basis-ID-Generator implementieren, die ich so nennen kann:Typ basierend Id-Generator mit Shapeless

val nextPersonId = idGen.id[Person] 

Ich würde IdGen wie ein Merkmal zu sein (wenn möglich):

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? 
} 

Wie soll man das mit Shapeless umsetzen?

Ich habe versucht, mit scala Reflexion TypTag und iterieren über die toString Ergebnis, aber es ist hässlich.

+0

Ich bin mir nicht ganz sicher, was Sie hier machen wollen. Soll der Compiler die IDs für Sie erhöhen? Soll der Compiler die Verwendung eines bestimmten ID-Generators einfach erzwingen? Ersteres wird nicht möglich sein, wenn IDs zur Laufzeit generiert werden sollen, da sich die Anzahl der generierten IDs möglicherweise auf Basis des Kontrollflusses ändert. Letzteres erfordert möglicherweise keine Shapeless, je nachdem, was Sie versuchen zu tun. – badcook

+0

@badcook Ich schreibe eine Antwort mit toString Parsing des TypeTag von L mich selbst, und es wird hoffentlich klarer :) – eirirlar

Antwort

0

Okay, hier ist der String-basierte Version, die wahrscheinlich Fehler in Bezug auf viele Eckfällen hat, und die erfordert Implementierer vorformulierten in Form eines impliziten TypeTag der Versorgung zu produzieren:

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 
    } 
} 

Einfache Testklasse:

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] 
    } 
} 

Es wäre sehr interessant, eine bessere Implementierung zu sehen.

Verwandte Themen