获取部分函数的已定义参数



假设我有一个局部函数(类似于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"}}

(这部分已经可以工作了)

现在,如果一个客户端已经定义了一个服务,而另一个客户端想知道该服务的可用方法,我现在需要知道服务接受什么样的case类,以便我可以告诉请求客户端。我知道我可以很容易地在对象中使用普通方法,但由于我如何解析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

漂亮的打印机:

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("*")的服务

如果你找到一个真正的解决方案使用宏或反射(或魔术),请张贴在这里!

您是否在问是否有可能获得Any参数的所有输入列表,这将导致匹配?如果这是你的问题,那么我相信答案是否定的。您所拥有的只是isDefinedAt,它告诉您如果提供给这个部分函数,arg是否会导致匹配,但这可能不是您想要的。

相关内容

  • 没有找到相关文章