2011-05-30 106 views
6

考慮下面的代碼:問題與斯卡拉匹配+範圍

case class ChangeSet(field:String, from:Object, to:Object) 

private var changed:List[ChangeSet] = Nil 

def change(field:String, from:Object, to:Object) { 
    changed.find{ case ChangeSet(field,_,_) => true } match { 
    case Some(ChangeSet(field,to,_)) => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 

行給我的麻煩是Some(ChangeSet(field,to,_))

它編譯,但似乎正在發生的事情是,斯卡拉是作爲通配符的佔位符填充它。我基於這樣的假設,即當我執行以下操作時,我收到錯誤to is already defined as value

我想要的是使用方法參數中的to來創建ChangeSet對象。

這可能嗎?

回答

7

當模式匹配的Scala解釋所有標識符開頭小寫佔位符,中值填充。要告訴Scala使用to作爲外部示波器的常數值,您需要用反引號將其包圍:`to`。或者,您可以將名稱to更改爲To,因爲Rex Kerr建議,但我更願意將我的變量保持爲小寫。

這應該工作:

def change(field:String, from:Object, to:Object) { 
    changed.find{ case ChangeSet(`field`,_,_) => true } match { 
    case Some(ChangeSet(`field`, `to`, _)) => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 
+2

反引號符號最棘手的部分是如何讓它在StackOverflow答案中正確顯示:-) – 2011-05-30 07:31:00

1

你不能在像這樣的模式中使用變量名稱。你必須首先將它匹配到一個新的變量,然後做一個明確的比較。

def change(field:String, from:Object, to:Object) { 
    changed.find{ case ChangeSet(f,_,_) => field == f } match { 
    case Some(ChangeSet(f,too,_)) if f == field && to == too => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 
+0

這並不完全正確的:你可以使用反引號標記,如[kassens的答案]所示(http://stackoverflow.com/questions/6172557/problem-with-scala-matching-scope/6173342#6173342)。 – 2011-05-30 07:30:02

+0

酷!何時添加? – 2011-05-30 08:29:27

+0

我不知道;因爲至少在兩年前至少:-) – 2011-05-30 08:50:59

1

如果在模式匹配中使用小寫名稱,Scala會填寫該值。如果你只想匹配,如果你有這個值,你需要使用一個大寫的名字。撇開你想要做什麼邏輯,並在名字的排序可疑的變化,你想:

def change(Field: String, from:Object, To: Object) { 
    changed.find{ 
    case ChangeSet(Field,_,_) => true 
    case _ => false // You need this line! No match is an exception, not false! 
    } match { 
    case Some(ChangeSet(Field,To,_)) => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 
4

看來這裏有兩個混淆。第一個是由Rex和Kim確定的。你可以從讀取this section編程Scala瞭解更多信息。它歸結爲:

x match { case Some(foo) => } // variable pattern, defines and binds variable foo 
x match { case Some(Foo) => } // constant pattern, based on val Foo 
x match { case Some(`foo`) => } // constant pattern for lowercase val 

你也可以使用一個後衛來約束比賽

x match { case Some(foo) if condition => } 

第二個困惑是要「從做一個變更對象通過方法參數「。如果我正確地理解了你,你正試圖使用​​case類語法構造一個對象:

ChangeSet(field, from, to) 

這不適用於模式匹配的那一邊。發生在案例一側的模式匹配事實上可以看作是構建ChangeSet的反向match { case ChangeSet(field, from, to) => }解構ChangeSet對象並將其零件分配到field,fromto值。當它是這樣組成的時候也是如此:Some(ChangeSet(field, from, to)),它首先解構Some然後ChangeSet。你可以看到,在值工作定義,因爲它是利用相同的解構機制:

scala> val cset = ChangeSet("a", "from", "to") 
cset: ChangeSet = ChangeSet(a,from,to) 

scala> val Some(ChangeSet(s, o1, o2)) = Some(cset) 
s: String = a 
o1: java.lang.Object = from 
o2: java.lang.Object = to 

看來你想要做的是建立一個新的對象,副本ChangeSet價值,但用單場。案例類支持這一帶copy,我REPL例如繼續:

scala> val cset2 = cset.copy(from = o2) 
cset2: ChangeSet = ChangeSet(a,to,to) 

考慮到這一點,這裏是change另一個建議:

def change(field:String, from:Object, to:Object) { 
    changed.find(_.field == field) match { 
    case Some(cset) => 
     val csetnew = cset.copy(from = to) 
     // do stuff with csetnew 
    case None => 
     // do stuff 
    } 
}