2011-12-26 88 views
1

我正在實現一些擴展Actor並提供一些額外功能的抽象類[1]。但是,模式匹配在接收語句中似乎不起作用。如果我從客戶端的形式的服務器發送的情況下,對象Connect到服務器,並且具有一個模式匹配:在Scala中擴展抽象遠程Actor和模式匹配(ClassLoading?)

println("Starting to receive, e.g. " + Connect.getClass.toString) 
receive { 
    case Connect => println("Got a connected message") 
    case m => println("Got something weird: " + m + " of type " + m.getClass.toString) 
} 

然後輸出是

Starting to receive, e.g. class ConnectionTest$Connect$ 
Got something weird: Connect of type class ConnectionTest$Connect$ 
... 

無法識別傳入消息作爲模式匹配中的Connect對象,即使getClass表示它是。更奇怪的是:mConnect具有相同的hashCode,並使用ObjectOutputStreamwriteObject序列化到完全相同的ByteArray,但不等於它(使用==)。我最好的猜測是classLoader在某種程度上表現得不正確,但我不知所措。

這裏是什麼,我想寫一個更完整的例子:

import scala.actors.{Actor, OutputChannel} 
import scala.actors.Actor._ 
import scala.actors.remote.RemoteActor 
import scala.actors.remote.RemoteActor._ 
import scala.actors.remote.Node 

abstract class ConnectionTest(masterNode: Node, port: Int) { 

    trait Message 
    case object Connect extends Message 

    abstract class Master extends Actor { 
    def act { 
     RemoteActor.classLoader = getClass.getClassLoader 
     alive(port) 
     register('MasterProcess, self) 

     while (true) { 
     println("Starting to receive, e.g. " + Connect.getClass.toString) 
     receive { 
      case Connect => println("Got a connect message") 
      case m => println("Got something weird: " + m + " of type " + m.getClass.toString) 
     } 
     } 
    } 
    } 

    abstract class Worker extends Actor { 
    def act { 
     RemoteActor.classLoader = getClass.getClassLoader 
     val master = select(masterNode, 'MasterProcess) 
     link(master) 
     master ! Connect 
    } 
    } 
} 

下面是一個例子使用:

object MyConnectionApp extends optional.Application { 

    case class MyConTest(hostname: String, port: Int) extends ConnectionTest(Node(hostname, port), port) { 
    case object MyMaster extends Master 
    case object MyWorker extends Worker 
    } 

    def main(master: Boolean) = { 
    if (master) 
     MyConTest("localhost", 2552).MyMaster start 
    else 
     MyConTest("localhost", 2552).MyWorker start 
    } 
} 

當我運行這個程序,輸出如上。從MyWorker遠程接收的Connect消息未被MyMaster的行爲方法中的模式匹配識別。儘管getClass.toString對它們的評估是一樣的,但它們在某種程度上並不相同。我怎樣才能解決這個問題?

[1]更多詳細信息:我正在爲大量節點上的某種並行計算實現框架。在更復雜的情況下,我實際上想用ParallelComputation[Data, Result]代替ConnectionTest,其中DataResult是類型參數。消息還包括依賴於這些參數的課,像

case object Computed(x: Data, y: Result) extends Message 

理想情況下,我想,隨着這種設計模式打得很好的解決方案。

+0

你有沒有試過阿卡和他們的遠程演員? 2.0我們看起來非常好。你可以嘗試案例類而不是案例對象嗎? – fmpwizard 2011-12-26 06:22:50

+0

你知道阿卡是否解決了這個問題?如果我將'Connect'更改爲一個case類,則會得到一個異常:'java.io.NotSerializableException:scala.actors.MQueue'。 – davidsd 2011-12-26 06:27:28

+0

[this](http://groups.google.com/group/akka-user/browse_thread/thread/48a2d6ce25e1aa2d)是遠程演員互相交談的一個工作示例,所以是的,他們正在做你正在嘗試做的事情 – fmpwizard 2011-12-26 16:46:11

回答

2

我還沒有測試,但我認爲你不應該把Message的特質和實現(包括對象Connect)放在類ConnectionTest中。您可以將它們放在伴侶對象中。如果你把它們放在一個類中,對於每個包含類ConnectionTest(並且在序列化的情況下更糟糕的情況下,它具有對該實例的引用)的每個實例,都有一個獨特的對象Connect

對象Connect屬於ConnectionTest的不同實例是不同的,並且不相互匹配。

+0

謝謝,這確實解決了這個問題。但是,我不明白爲什麼ConnectionTest的實例是不同的。你能在這裏解釋規則嗎? – davidsd 2011-12-27 01:46:25

+0

對象的平等是默認引用相等。我認爲這是正確的行爲。所以只要有兩個包含類的實例,那些實例是相等的,它們包含的對象不是相關的。 – 2011-12-27 09:32:29