scala - 获取偏函数的定义参数

标签 scala reflection

假设我有一个偏函数(类似于 Akka 的接收方法的 Actor )

def receive: PartialFunction[Any, Unit] = {
    case SomeCaseClass(params) => println("whatever")
}

有没有办法获得这个函数的所有定义的参数?

我正在实现类似服务结构的 JSON RPC。我基本上希望客户能够定义
通过部分功能的服务。
def clientService = {
    case Connect(login, password) =>.....
    case SomeMessage => ...
    case SomeMethod(bla) => ..
}

例如第一种方法将从
{method: "connect", params:{login: "asdsad", password: "adsada"}}

(这部分已经工作了)

现在,如果一个客户定义了一个服务,而另一个客户想知道该服务的可用方法,我现在需要知道该服务接受什么样的案例类,以便我可以告诉请求的客户。我知道我可以使用对象中的普通方法轻松完成此操作,但是由于我解析 JSON 并将其转换为 case 类的方式,部分函数将简化我的 API,我喜欢漂亮的代码;)

另外,我很确定必须有一种通过反射的方法,尽管我不知道在编译/运行时如何表示部分函数。

最佳答案

根据您可以或愿意对您的服务做出多少假设,这里有一种完全不复杂的方法,但可能仍然是一种选择。它基本上依赖于 1) 已知所有可能的消息类型和 b) 部分函数仅在一维中是部分的(稍后会详细介绍)。

我们需要一组有限的可能的消息类型:

sealed trait Message

case class Hello(who: String) extends Message
case class Lunch(withWhom: String) extends Message
case class Dinner(withWhom: String) extends Message
case class Goodbye(who: String) extends Message

以及一些示例服务:
val service0: PartialFunction[Any, Unit] = {
  case Hello(who) => ()
  case Goodbye(who) => ()
}

val service1: PartialFunction[Any, Unit] = {
  case Hello(who) => ()
  case Lunch(withWhom) => ()
  case Goodbye(who) => ()
}

var services = List(service0, service1)

接下来,我们还定义了一个消息实例列表,用作接受消息的蓝图:
val simpleInstances = List(Hello("*"), Lunch("*"), Dinner("*"), Goodbye("*"))

最后,我们定义了一个方法,该方法从偏函数和可能的参数列表中返回接受的参数:
def supportedArguments[F, T, A <: F]
                      (pf: PartialFunction[F, T], args: Iterable[A]) =

  args filter pf.isDefinedAt

pretty-print :
def printSupportedArguments(services: Iterable[PartialFunction[Any, Unit]],
                            messages: Iterable[Message]) {

  services.zipWithIndex.foreach {case (s, i) =>
    val supported = supportedArguments(s, messages)
    println(s"Service $i supports $supported")
  }
}

我们走吧:
printSupportedArguments(services, simpleInstances)
  // Service 0 supports List(Hello(*), Goodbye(*))
  // Service 1 supports List(Hello(*), Lunch(*), Goodbye(*))
  // Service 2 supports List(Goodbye(*))

如果服务不仅在它们接受的消息类型方面是不完整的,而且在它们接受的消息内容方面也是不完整的,也就是说,如果它们在多个方向上是不完整的,事情就会变得更加复杂:
val service2: PartialFunction[Any, Unit] = {
  case Hello("Thomas") => ()
  case Hello("Laura") => ()
  case Goodbye(who) => ()
}

这样的服务还需要对蓝图实例列表进行调整:
val moreInstances = simpleInstances ++ List(Hello("Thomas"), Hello("Laura"))

导致:
printSupportedArguments(services :+ service2, moreInstances)
  // Service 0 supports List(Hello(*), Goodbye(*), Hello(Thomas), Hello(Laura))
  // Service 1 supports List(Hello(*), Lunch(*), Goodbye(*), Hello(Thomas), 
  //                         Hello(Laura))
  // Service 2 supports List(Goodbye(*), Hello(Thomas), Hello(Laura))

这种方法的一系列缺点显然包括以下几点:
  • 必须知道消息类型
  • 如果服务在多个维度上是局部的,则必须知道所有可能的消息内容
  • 使用实例 Hello("*")表示 Hello 的任意实例使得无法区分接受 Hello(_) 的服务和服务,只接受Hello("*")

  • 如果您使用宏或反射(或魔法)找到真正的解决方案,请在此处发布!

    关于scala - 获取偏函数的定义参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16544127/

    相关文章:

    scala - 仅显示 DateTime 值的年月日

    scala - 用匹配器计数

    scala - 为递归方法生成Scala AST

    scala - 函数式编程标量

    scala - Scala的getter/setter方法出现问题

    c# - typeof(T).AssemblyQualifiedName 返回 null

    java - 在 Java 中反射(reflect)方法的 Action

    java - 使用Reflection API是否会使Java的安全性降低?

    java - 如何通过Java中的Reflection API加速类扫描?

    c# - GetMethod 当参数通过引用出现时