2013-05-14 59 views
4

說我有一個部分功能(類似於阿卡對演員接受法)獲取定義參數部分功能

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並將其轉換爲案例類,因此部分函數會簡化我的API並且我喜歡漂亮的代碼;)

加上我很漂亮確定必須通過反射來實現,儘管我不知道在編譯/運行時如何表示局部函數。

+0

我有我的懷疑,有一天有人瘋了會拿出一個宏,給你的信息:) – 2013-05-15 00:17:18

+0

是的,但暫時我試圖自己實現它。由於在2.10中反射的文檔有點缺乏,可能需要一段時間;) – rawphl 2013-05-15 05:24:10

回答

1

你問是否有可能獲得Any參數的所有輸入的列表,這將導致匹配?如果這是你的問題,那麼我相信答案是否定的。你所擁有的全部是isDefinedAt告訴你,如果提供給這個部分函數的參數會導致匹配,但這可能不是你要找的。

+0

@cmdbaxter是的,這正是我想要做的。我認爲這應該是可能的反思或宏,但我不知道如何。 – rawphl 2013-05-14 13:34:00

+0

請問您的用例是否需要識別部分函數的所有可能的匹配變體?我總是不知道自己在說什麼,但我不認爲反思能夠告訴你你在找什麼。如果我理解你的用例,也許我可以提供一個備用解決方案。 – cmbaxter 2013-05-14 14:02:20

+0

我添加了一個解釋。 – rawphl 2013-05-14 14:21:48

3

取決於您可以或願意對您的服務進行多少假設,這裏是一種完全不成熟的方法,可能仍然是一種選擇。它基本上依賴於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("*")) 

最後,我們定義了一個方法,該方法返回acceptte從部分功能d參數和可能的參數列表:

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)) 

設定這種做法明顯的缺點包括以下內容:

  • M essage類型必須是已知的

  • 如果服務在多個維度是局部的,所述的所有可能的消息內容必須是已知的,以及

  • 使用實例Hello("*")表示任意實例的Hello使得不可能服務之間進行區分接受Hello(_)和服務,從字面上只接受Hello("*")

你會發現使用宏或反射(或魔法),請在這裏發表一個真正的解決方案!