2011-07-04 53 views
3

是否有可能基於Scala中的另一個清單定義清單?是否有可能基於Scala中的另一個清單定義清單?

我已經非常想讓自己相信,這是不可能的,因爲Scala Manifest信息並非旨在動態使用。

這是問題所在。我有一個函數可以返回多個類型的對象(String,Int,List [Int],List [List [String]]等)。爲了支持這些多種類型,返回類型設置爲Any,但是到期要輸入刪除,有關列表,地圖等支持類型的信息將丟失。爲了恢復一些細節,我返回一個Manifest和返回類型。

但是,返回的信息可能會放在另一個列表或映射中,然後從另一個函數返回。我想要更新清單以包含這樣的事實,即該類型現在是由清單定義的以前類型的List或Map。

下面是一些示例代碼

def returnWithManifest[T: Manifest](x: T) = (x, manifest[T]) 

// May return String, Int, List[Int], List[List[String]], ... 
def contrivedExample(t: String): (Any, Manifest[_]) = t match { 
    case "String" => returnWithManifest("test") 
    case "Int" => returnWithManifest(1) 
    case "Boolean" => returnWithManifest(true) 
    case "List[Int]" => returnWithManifest(List(1,2,3)) 
    case "List[List[String]]" => 
    returnWithManifest(List(List("a","b"),List("c","d"))) 
    case _ => returnWithManifest(None) 
} 

scala> val v1 = contrivedExample("List[Int]") 
v1: (Any, Manifest[_]) = (List(1, 2, 3),scala.collection.immutable.List[Int]) 

scala> val x = v1._1 
x: Any = List(1, 2, 3) 

scala> val m = v1._2 
m: scala.reflect.Manifest[_] = scala.collection.immutable.List[Int] 

scala> val v2 = List(x) 
v2: List[Any] = List(List(1, 2, 3)) 

從「V1」的清單我知道V1的類型是List [INT]的,所以當我創建「V2」我應該有我需要創建的所有信息清單標識類型是List [List [Int]],但是我只有List [Any]可用。也許類似下面的語法:

val v2: m = List(x) 
val v2 = List[m](x) 

我知道它看起來像我試圖動態定義類型,但在現實中的信息輸入靜態已知類型的刪除相關的元數據。我猜如果這可以解決,然後類型擦除可以解決。但是,最起碼,我想我應該可以做這樣的事情:

scala> val m2 = m.wrapInList() 
m2: scala.reflect.Manifest[_] = 
     scala.collection.immutable.List[scala.collection.immutable.List[Int]] 
+0

我真的很想知道什麼約束會促使你使用這種奇怪的設計? – paradigmatic

回答

5

編輯:阿德里安·摩爾是正確的指出這個工程:

def makeListManifest[T: Manifest] = manifest[List[T]] 

你只需要顯式調用它,通過它你已經獲得了明顯的。


我以前的答案:

huynhjl是部分正確的:目前這不會自動工作。我們需要編譯器足夠聰明來編譯它:

def makeListManifest[T](m: Manifest[T]) = manifest[List[T]] 

沒有任何額外的隱式參數。儘管看起來可行(所有需要的信息在這裏),但它尚未實現(2.9.0.1),因爲如果編譯器具有它需要的所有靜態類型信息或者查找隱式作用域,但不是從其他(可能是隱式可用的)清單生成的。

你能做什麼,但是,是構建一些表現自己與同伴對象的方法:

scala> import reflect.Manifest 
scala> Manifest.classType(classOf[List[_]], manifest[Int]) 
res0: scala.reflect.Manifest[List[_]] = scala.collection.immutable.List[Int] 

所以可以實現makeListManifest自己:

scala> def makeListManifest[T](m: Manifest[T]) = Manifest.classType(classOf[List[_]], m)    
makeListManifest: [T](m: scala.reflect.Manifest[T])scala.reflect.Manifest[List[_]] 

注意,雖然權清單將被返回,makeListManifest的靜態返回類型僅爲Manifest[List[_]]。但您可以在這裏安全地投入Manifest[List[T]]

+0

我想你只是在參數列表中忘記了隱式修飾符。這對我有效:'def makeListManifest [T:Manifest] = manifest [List [T]]' –

+0

@Adriaan哦,拍 - 當然你是絕對正確的。 –

+0

我認爲這會做到這一點,謝謝 – Mike

1

我想是因爲你的函數返回清單[_],編譯器已經失去了必要的信息來恢復的數據類型。如果mManifest[List[Int]]類型,那將是一個不同的故事。

+0

確實如此,但您可以使用伴隨對象上的方法自行構造清單。 –

5

請注意,斯卡拉的類型系統允許你做得比返回Any更好。定義類型聯盟有多種方式(又稱「析取類型」)。見例如

當然,你也可以有自己的ADT返回類型,這是恕我直言乾淨的解決方案:

trait ReturnValue 
case class ReturnInt(value: Int) extends ReturnValue 
case class ReturnString(value: String) extends ReturnValue 
case class ReturnIntList(value: List[Int]) extends ReturnValue 
... 

[編輯]

從第二個鏈接的定義去,我們可以這樣寫:

def contrivedExample(t: String): String or List[Int] or List[List[String]] = t match { 
    case "String" => "test" 
    case "List[Int]" => List(1,2,3) 
    case "List[List[String]]" => List(List("a","b"),List("c","d")) 
} 

現在我們可以冗長檢索,但安全類型:

def otherContrivedExample(t: String or List[Int] or List[List[String]]) = t match { 
    case DisjointType(Some(DisjointType(Some(s),_)), _) => println("processing String: " + s) 
    case DisjointType(Some(DisjointType(_,Some(s))), _) => println("processing List[String]: " + s) 
    case DisjointType(_,Some(s)) => println("processing List[List[Int]]: head=" + s.head) 
} 

val x = contrivedExample("List[List[String]]") 
otherContrivedExample(x) 
//--> processing List[List[Int]]: head=List(a, b) 

正如你可以看到匹配的變量s有正確的類型,儘管我們沒有提到它。我很確定提取過程可以通過使用隱式魔法和/或特殊提取器來簡化。

+0

如果您可以詳細闡述一下如何使用您的鏈接中描述的內容來實現聯合類型作爲方法的返回類型,我會感興趣。 –

+0

@ Jean-Philippe Pellet:請參閱我的編輯。 – Landei

+0

非常感謝!太糟糕了,模式匹配部分太冗長了。 –

相關問題