问题
We have a trait that among other things contains an execute[T <: Record](Seq[(Session) => T]): Seq[T]
method, where Record
is the supertrait of all traits that we're retrieving from the database
trait DbTrait {
val threadCount: Int
val db: Database
protected def getGroupSize(size: Int, threadCount: Int) {
(size / threadCount) + if(size % threadCount == 0) 0 else 1
}
def execute[T <: Record](funs: Seq[(Session) => T]): Seq[T]
}
trait DbTraitSingle extends DbTrait {
val threadCount = 1
def execute[T <: Record](funs: Seq[(Session) => T]): Seq[T] =
db.withSession{session: Session => funs.map(f => f(session))}
}
trait DbTraitMulti extends DbTrait {
val threadCount = 4
def execute[T <: Record](funs: Seq[(Session) => T): Seq[T] =
funs.grouped(getGroupSize(funs.size, threadCount)).map(funs => Future {
db.withSession{session: Session => funs.map(f => f(session))}
}.toList.flatten
}
and so on. Ideally we'd like to be able to create something like a
def executePoly2[T1 <: Record, T2 <: Record]
(tuple: Tuple2[(Session) => T1, (Session) => T2]): Tuple2[T1, T2]
for arbitrary tuples (i.e. an executePoly3, executePoly4, etc), but there are two problems:
- Is there a way to reduce the amount of boilerplate here, or would we be stuck creating 22 different method signatures?
- Is there a type-safe way to split up a tuple similar to the
seq.grouped
method call, or are we stuck having special cases for all of the differentthreadCount
values (which at present doesn't exceed 4)?
回答1:
You can get to something very easy to use using the Shapeless library by Miles Sabin. See what they can do with a Tuple. Specifically abstracting over arity.
import syntax.std.tuple._
import poly._
var myProducedTuple = myTuple map (_(session))
来源:https://stackoverflow.com/questions/22411368/type-safe-way-to-divide-a-tuple-into-multiple-tuples