我的代码会在我的应用中重复多次(超过15次)。
val entityList = params.map(paramPair => {
//THIS LINE DEPENDS ON THE ENTITY
val entityX = new Entity1
paramPair.foreach { case (key, value) => (key, value) match {
//THIS BLOCK CHANGES DEPENDING THE ENTITY
case (KEY1, v: TYPE1) => entityX setX v
case (KEY2, v: TYPE2) => entityX setY v
...
//END BLOCK
case _ =>
}
}
entityX
})
唯一更改的代码是实体类型和模式匹配case子句。有没有办法创建一个接收这些案例的函数来避免代码重复?
答案 0 :(得分:1)
你可以转
paramPair.foreach { case (key, value) => (key, value) match {
//THIS BLOCK CHANGES DEPENDING THE ENTITY
case (KEY1, v: TYPE1) => entityX setX v
case (KEY2, v: TYPE2) => entityX setY v
...
//END BLOCK
case _ =>
}
}
到
paramPair.foreach { case (key, value) =>
case (KEY1, v: TYPE1) => entityX setX v
case (KEY2, v: TYPE2) => entityX setY v
...
//END BLOCK
case _ =>
}
}
如果您对匿名课程没问题,可以将整个代码转换为:
val entityList = params.map(paramPair => {
new Entity1 {
paramPair.foreach { case (key, value) =>
//THIS BLOCK CHANGES DEPENDING THE ENTITY
case (KEY1, v: TYPE1) => setX v
case (KEY2, v: TYPE2) => setY v
...
//END BLOCK
case _ =>
}
}})
如果块的变化取决于实体,你可以像@pst所说的那样,使用所谓的函数文字变成函数:带花括号的表达式和case语句将变成PartialFunction,例如:
val fillEntitityOne: PartialFunction[A,B] = {
case (KEY1, v: TYPE1) => entityX setX v
case (KEY2, v: TYPE2) => entityX setY v
}
A和B输入和返回类型,例如
val foobar: Int => String = { case 1 => "1" }
这就是为什么你可以在第二个片段中省略匹配部分的原因:foreach期望Function实例(和PartialFunction继承自Function),当然还有一些类型,所以实际上我们可以desugar
.foreach {
case x =>
}
到
.foreach({
case x =>
})
然后
val anon = new PartialFunction[A,B]{....}
.foreach(anon)
答案 1 :(得分:1)
只是为了好玩。因为关键是要玩得开心吧?
由于我忘记了如何使用可变字段,我更喜欢构造不可变的Dog。
Impersonator可以通过重构PartialFunction来扩展AnyVal(因为AnyVal不允许匿名嵌套类,“计划在后续版本中删除此限制。”)
package populate
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
import java.util.{ Calendar, Date }
case class Person(var name: String, var birth: Date) { def this() = this(null,null) }
case class Book(var title: String, var pub: Date) { def this() = this(null,null) }
case class Dog(val name: String, val rabies: Date, val goodBoy: Boolean = true)
object Test extends App {
def dateOf(y:Int,m:Int,d:Int) = { val c = Calendar.getInstance; c.set(1974, 2, 14); c.getTime }
val input = Seq("id" -> "Sybil", "n" -> dateOf(1974, 2, 14), "garbage" -> "error")
trait Completer[A] extends Any {
def filler: PartialFunction[A, Unit]
def complete(info: Seq[A]) = info foreach (filler orElse {
case (k, v) => println(s"Can't use $k -> $v")
})
}
type Info = (String, Any)
implicit class Impersonator(val p: Person) extends Completer[Info] {
override def filler = {
case ("id", s: String) => p.name = s
case ("n", d: Date) => p.birth = d
}
}
implicit class Booker(val b: Book) extends Completer[Info] {
override def filler = {
case ("id", s: String) => b.title = s
case ("n", d: Date) => b.pub = d
}
}
def personify(p: Person, info: Seq[(String, Any)]) = info foreach {
case ("id", s: String) => p.name = s
case ("n", d: Date) => p.birth = d
case (k, v) => println(s"Can't use $k -> $v")
}
def bookish(b: Book, info: Seq[(String, Any)]) = info foreach {
case ("id", s: String) => b.title = s
case ("n", d: Date) => b.pub = d
case (k, v) => println(s"Can't use $k -> $v")
}
def inject[A: ClassTag](a: A, info: Seq[(String, Any)]): A = {
implicitly[ClassTag[A]] match {
case ClassTag(k) if k == classOf[Person] => personify(a.asInstanceOf[Person], info)
//case ClassTag(k) if k == classOf[Book] => bookish(classOf[Book] cast a, info)
case ClassTag(k) if k == classOf[Book] => a.asInstanceOf[Book] complete info
case k => println(s"Unknown $k")
}
a
}
def entity[A: ClassTag](info: Seq[(String, Any)]): A = {
val e = implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A]
inject(e, info)
}
val v = entity[Person](input)
println(v)
Console println entity[Book](input)
Console println Defaulter((input map {
case ("id", v) => ("name", v)
case ("n", v) => ("rabies", v)
case p => p
}).toMap).newCase[Dog]
}
case class Defaulter(input: Map[String, Any]) {
def newCase[A]()(implicit t: ClassTag[A]): A = {
val claas = cm classSymbol t.runtimeClass
val modul = claas.companionSymbol.asModule
val im = cm reflect (cm reflectModule modul).instance
defaut[A](im, "apply")
}
def defaut[A](im: InstanceMirror, name: String): A = {
val at = newTermName(name)
val ts = im.symbol.typeSignature
val method = (ts member at).asMethod
// either defarg or default val for type of p
def valueFor(p: Symbol, i: Int): Any = {
val defarg = ts member newTermName(s"$name$$default$$${i+1}")
if (input contains p.name.toString) {
input(p.name.toString)
} else if (defarg != NoSymbol) {
println(s"default $defarg")
(im reflectMethod defarg.asMethod)()
} else {
println(s"def val for $p")
p.typeSignature match {
case t if t == typeOf[String] => null
case t if t == typeOf[Int] => 0
case t if t == typeOf[Date] => new Date(0L)
case x => throw new IllegalArgumentException(x.toString)
}
}
}
val args = (for (ps <- method.paramss; p <- ps) yield p).zipWithIndex map (p => valueFor(p._1,p._2))
(im reflectMethod method)(args: _*).asInstanceOf[A]
}
}