1

我試着去創建一個解析器的小語種與命令包括標籤和GOTO:Scala中追加一個標籤不變的情況下,類

... 
lazy val cmds = opt("{")~>rep(cmd<~opt(";"))<~opt("}") ^^ {...} 
lazy val cmd = ("if"~boolexpr~"then"~cmds~"else"~cmds 
    ^^ { case _~b~_~c1~_~c2 => IFCMD(boolexpr,c1 
| ident ~":="~numericLit ^^ {case i1~_~v => ASSIGN(i1,v) } 
| "goto" ~>ident ^^ { case l => GOTO(l) } 
| ident~":"~cmd ^^ { case l~_~c => <APPENDLABELTO_CORE> 
... 

GOTOIFCMD等都是延長抽象類case類Core

與功能/斯卡拉樣/不可改變objecty保持-WAY我在想,定義Core這樣是錯誤的

abstract class Core(var label:Option[String] = None) 

,但會允許我用<APPENDLABELTO_CORE>與更換部件:

| ident~":"~cmd ^^ { case l~_~c => c.label = Some(l); c } 

任何人都可以指出「scalaish」的方式來做到這一點?

(我試過c copy (label=Some(l))但抽象基類還沒有得到自動拷貝構造函數魔法)

回答

4

這是完全有可能創建自己的副本樣方法:使用

abstract class Core(val label: Option[String]) { 
    def set(label: Option[String]): Core 
} 
class Impl(label: Option[String] = None) extends Core(label) { 
    def set(label: Option[String] = this.label) = new Impl(label) 
} 

因此:

scala> val i = new Impl 
i: Impl = [email protected] 

scala> i.label 
res0: Option[String] = None 

scala> i.set(label = Some("thing")) 
res1: Impl = [email protected] 

scala> res1.label 
res2: Option[String] = Some(thing) 

但是,務實的是,我不會太快地放棄在這裏使用變量。據我所知,理解關於不可變值的理由比較容易,但在解析器中得到的結果是非常好的。另一種想法是創建一種方法,在最後將所有內容都轉換爲不可變的版本,或者解析器代碼最終將所有數據存儲在其他地方,只需將其保留爲可變。

另一種方法是讓抽象類不抽象,但實際上使它成爲一個案例類。您可以從案例類派生類(然而,從案例類派生案例類是一個禁忌)。然後,訣竅就是讓您的可變數據可以在現場保存:

abstract class SpecializedStuff { } 
case class ParticularStuff(val i: Int) extends SpecializedStuff 
case class Core(details: SpecializedStuff, label: Option[String] = None) 
class Impl(p: ParticularStuff) extends Core(p) 

scala> val i = new Impl(ParticularStuff(5)) 
i: Impl = Core(ParticularStuff(5),None) 

scala> i.copy(label = Some("thing")) 
res0: Core = Core(ParticularStuff(5),Some(thing)) 
相關問題