2011-05-14 49 views
6

我尋找,需要一個功能FUNC的方法正確的簽名和參數ARG,複製他們在網絡上的遠程計算機並返回結果。目前,該簽名是這樣的:序列化和AnyVal

def invokeRemote[A,B](address: String, func: A => B, arg: A): B 

這樣做的問題是,該方法將拋出一個異常NotSerializable如果參數不是序列化或Java的基本類型之一。

我想出了以下解決方案,以趕在編譯時這個錯誤...

type Func = (A => B) with Serializable 

def invokeRemote[A <: Serializable, B <: Serializable](address: String, func: Func, arg: A): B 

...但現在是不可能的了傳遞類型的參數AnyVal詮釋浮動不明確實現Serializable接口

方法簽名應該是什麼樣子等,使得它僅接受序列化對象或類型AnyVal的對象作爲參數?

回答

9

您可以將context bound隱含在自定義特徵中,併爲該特徵提供AnyValSerializable的隱式轉換。

trait Ser[M] 

implicit def toSer1[T <: AnyVal]: Ser[T] = new Ser[T] {} 
implicit def toSer2[T <: java.io.Serializable]: Ser[T] = new Ser[T] {} 

def f[T: Ser](a:T): T = a 
f(1) 
// res2: Int = 1 
f("123") 
// res3: java.lang.String = 123 
f(new Object) 
// could not find implicit value for evidence parameter of type Ser[java.lang.Object] 

編譯器會基於類型的隱含參數,因爲有些提供了T <: AnyValT <: java.io.Serializable它會在這種情況下進行編譯。

你能堅持隱含定義爲Ser同伴對象,讓他們可在需要的地方。

然後,您的簽名變成了:

def invokeRemote[A:Ser, B:Ser](address: String, func: A => B, arg: A): B 
+0

哇,謝謝你這個非常好的解決方案。看到Scala編譯器能夠做什麼:) – gruenewa 2011-05-14 16:22:53

1

使用序列化的參數類型在實踐中行不通,因爲你可以有序列化的情況下,是不是其實序列化:

class NotSerializable(val s: String) 

// ArrayList inherits Serializable 
val list = new java.util.ArrayList[NotSerializable]() 

list.add(new NotSerializable("test")) 

// will fail at run time 
serialize(list) 

此外, Scala集合特性不會繼承Serializable(實現)。

def f(s: Serializable) { println(s) } 

// will fail to compile, because interface List does not inherit Serializable 
f(List("a", "b")) 

// will print true because list implementation is Serializable 
println(List("a", "b").isInstanceOf[Serializable]) 

正在Serializable是一個運行屬性,不能單獨由類型強制執行。使用Serializable作爲參數類型不會將您從運行時序列化錯誤中解救出來。你所要做的就是讓你的函數更難調用,因爲你已經體驗到了AnyVal(這只是冰山一角)。

0

這聽起來可能offtopic和怪異,但我會建議考慮通過周圍沒有Java二進制文件的代碼,但是,比如說,JavaScript代碼(也許在其coffescript形式),並在執行方面使用犀牛。

有對於深層次原因,如打字lambda表達式是用於內部和非類型化的交流,但沒有理論呢。