2013-10-18 77 views
0

在約RegexParsers的Scaladoc,有下面的代碼:爲什麼RegexParsers用「def」而不是「lazy val」來定義?

object Calculator extends RegexParsers { 
    def number: Parser[Double] = """\d+(\.\d*)?""".r ^^ { _.toDouble } 
    def factor: Parser[Double] = number | "(" ~> expr <~ ")" 
... 

我不明白爲什麼我們把它與一個def書面和不與vallazy val?我會這樣寫:

object Calculator extends RegexParsers { 
    lazy val number: Parser[Double] = """\d+(\.\d*)?""".r ^^ { _.toDouble } 
    lazy val factor: Parser[Double] = number | "(" ~> expr <~ ")" 
... 
+0

def定義的開銷要小得多,因爲它們被編譯到通常的方法調用中,而懶惰的vals已經在下面檢查了初始化和bitset字段。 –

+0

但是'def'意味着每次都會重新創建正則表達式。難道這不會導致一些性能損失? – n1r3

+2

避免過早優化。此外,不要指望Scaladoc中的代碼示例可以隨時複製到您的生產應用程序中而無需修改! –

回答

1

它有一個實際的語義原因。看看類型簽名Parser

abstract class Parser[+T] extends (Input) ⇒ ParseResult[T] 

Parser[T]其實從一些抽象形式的InputParseResult[T]功能。在許多情況下(可能是大多數情況下),這個函數捕捉正在執行的解析狀態的某些方面。如果在val(懶惰或其他)中捕獲到這樣的產品,則它不能用於給定分析樹中的多個位置。唯一可以製作的作品val是固定終端,如標點符號和關鍵字。

附錄

已經有好幾年,因爲我已經在斯卡拉組合子解析器工作,我是比較的時候Scala的新手,所以這是完全有可能我只是錯了。但是,我的回憶是,Reader不是整個輸入,而是代表該輸入的特定子序列。因此,如果生產沒有固定的輸入序列,則生產不能是val

我其實有一個需要解析器的小項目,所以當我有一些時間時,我可以確認或反駁這種理解。

+1

這不是我的經驗。我使用惰性vals(或val)作爲我的分析器定義,並且由於「捕獲狀態」而無法記憶曾經有過的問題。我的理解是,輸入的狀態和解析結果足以在解析器之間傳遞狀態信息,因此解析器本身不需要記憶任何東西。你有一個具體的例子,說明哪裏出了問題? – inkytonik

相關問題