2010-07-13 87 views
2

您將如何實現通過正則表達式解析某些輸入並將已創建的字符串轉換爲其他類型的類?我的做法是:具有通用返回類型的可選函數參數

class ARegex[T](regex:Regex, reform:Option[String => T]){ 
    def findFirst(input:String):Option[T] = { 
    (regex.findFirstIn(input), reform) match{ 
     case (None, _) => None 
     case (Some(s), None) => Some(s) // this won't compile because of type mismatch 
     case (Some(s), Some(fun)) => Some(fun(s)) 
    } 
    } 
} 

class BRegex[T](regex:Regex, reform:Option[String => T]) { 
    def findFirst(input:String) = { //returns Option[Any] - erasure 
    (regex.findFirstIn(input), reform) match{ 
     case (None, _) => None 
     case (Some(s), None) => Some(s) 
     case (Some(s), Some(fun)) => Some(fun(s)) 
    } 
    } 
} 
+2

'T'可以是任何東西。 「T」和「String」的唯一常見超類型是「Any」。如果您有時想返回'Some [String]'和其他時間'Some [T]'(或'None'),那麼'Option [Any]'可以說'findFirst'的返回類型。 – 2010-07-13 15:38:09

+0

爲了開心看看:http://github.com/league/scala-type-anxiety/blob/master/src/RegexMatchCPS.scala – oluies 2010-07-13 22:02:37

回答

7

我們可以通過消除reformOption部分解決這個問題的類型,並使用不同的機制來表示我們不希望以任何方式更改匹配,這種機制是使用identity作爲默認參數,或者當您不希望類型更改時傳遞身份標識

class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){ 
    def findFirst(input:String):Option[T] = { 
    regex.findFirstIn(input) match{ 
     case None => None 
     case Some(s) => Some(reform(s)) 
    } 
    } 
} 

new ARegex("something".r).findFirst("something else") //returns Option[String] 
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int] 
+0

哦,我喜歡這個!我沒有想到將身份用作默認參數。 – 2010-07-13 21:11:15

+1

雖然你可以將'findFirst'的主體重寫爲'regex findFirstIn input map reform'。它真的會炫耀斯卡拉優雅。 – 2010-07-13 21:15:30

+1

@丹尼爾,這可能是寫出它最習慣的方式。我沒有這樣做(實際上,我做了,但恢復了它...檢查編輯歷史記錄),因爲我覺得如果我偏離原來的太多,它可能會掩蓋我答案的重要部分。 – 2010-07-13 23:30:38

2

好了,問題是類型不匹配,因爲你是返回無論是StringT,其中,當然,是在Any統一。您不能說您要返回Option[T],然後返回Option[String]

除此之外,該代碼的簡化版本是這樣的:

class ARegex[T](regex: Regex, reform: Option[String => T]) { 
    def findFirst(input: String): Option[Any] = 
    regex findFirstIn input map { s => reform map (_(s)) getOrElse s } 
} 

你可以返回一個Option[Either[String, T]],雖然。代碼將如下所示:

class ARegex[T](regex: Regex, reform: Option[String => T]) { 
    def findFirst(input: String): Option[Either[String, T]] = 
    regex findFirstIn input map { s => reform map (_(s)) toRight s } 
} 
1

爲什麼選擇[String => T]而不是String => T?如果您沒有傳入用於創建所需類型實例的機制,則運行時系統無法實際創建適當的對象。如果你真的需要傳遞一個選項[字符串=> T],那麼你的第二個案例應該簡單地返回None。

此外,flatMap是你的朋友,並會給你正確的行爲(即,如果改革沒有,則該方法返回無。

class RegexExtractor[T](regex: Regex, reform: Option[String => T]) { 
    def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f)) 
} 
+1

我不認爲正確的行爲是'findFirst'返回'無'如果'改革'是'沒有'。他正在尋找一種方法來省略「改革」功能,並在這種情況下讓findFirst跳過這一轉變。 – 2010-07-13 23:38:04

相關問題