首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有没有办法重构这个大小写匹配函数?

有没有办法重构这个大小写匹配函数?
EN

Stack Overflow用户
提问于 2012-12-27 03:47:48
回答 2查看 492关注 0票数 0

我有这段代码,它会在我的应用程序中重复多次(超过15次)。

代码语言:javascript
复制
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子句匹配的模式。有没有一种方法可以创建一个接收这些情况的函数来避免代码重复?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-12-27 13:19:08

只是为了好玩。因为重点是找乐子,对吧?

因为我忘记了如何使用可变字段,所以我更喜欢构造不可变的Dog。

模拟器可以通过重构AnyVal来扩展PartialFunction (由于AnyVal不允许匿名嵌套类,“计划在后续版本中删除此限制”)。

代码语言:javascript
复制
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]
  }
}
票数 1
EN

Stack Overflow用户

发布于 2012-12-27 04:54:17

你可以转身

代码语言:javascript
复制
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 _ =>
  }
}

转到

代码语言:javascript
复制
paramPair.foreach { case (key, value) => 
  case (KEY1, v: TYPE1) => entityX setX v
  case (KEY2, v: TYPE2) => entityX setY v
  ...
  //END BLOCK
  case _ =>
  }
}

如果你对匿名类没意见,你可以进一步把整个代码转换成:

代码语言:javascript
复制
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,例如

代码语言:javascript
复制
val fillEntitityOne: PartialFunction[A,B] = {
  case (KEY1, v: TYPE1) => entityX setX v
  case (KEY2, v: TYPE2) => entityX setY v
}

其中A和B输入和返回类型,例如

代码语言:javascript
复制
val foobar: Int => String = { case 1 => "1" }

这就是为什么你可以省略第二个代码片段中的匹配部分: foreach期望函数实例( PartialFunction继承自函数),当然还有一些类型,所以实际上我们可以

代码语言:javascript
复制
.foreach {
  case x => 
}

转到

代码语言:javascript
复制
.foreach({
  case x => 
})

然后

代码语言:javascript
复制
val anon = new PartialFunction[A,B]{....}
.foreach(anon)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14045463

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档