2010-02-11 57 views
16

在編譯使用Scala 2.7.3下面的代碼,爲什麼Scala的分號推斷在這裏失敗?

package spoj 

object Prime1 { 
    def main(args: Array[String]) { 
    def isPrime(n: Int) = (n != 1) && (2 to n/2 forall (n % _ != 0)) 
    val read = new java.util.Scanner(System.in) 
    var nTests = read nextInt // [*] 
    while(nTests > 0) { 
     val (start, end) = (read nextInt, read nextInt) 
     start to end filter(isPrime(_)) foreach println 
     println 
     nTests -= 1 
    } 
    } 
} 

我得到以下編譯時錯誤:

PRIME1.scala:8: error: illegal start of simple expression 
    while(nTests > 0) { 
    ^
PRIME1.scala:14: error: block must end in result expression, not in definition 
    } 
^
two errors found 

當我添加在該行的最後一個分號評論爲[*],該程序編譯好。任何人都可以請解釋爲什麼Scala的分號推斷無法在該特定行上工作?

+1

只是場外的話題,'2到n/2'可以被替換成'2 Math.sqrt(N)' - 這是典型的解決方案,雖然我不知道這是否會提供更好的性能(我想,它不會)。 – incarnate 2010-02-14 07:57:16

+0

我知道這是一箇舊線程,但是你能否明確地在'read nextInt'後面加分號?或者這是一個問題,因爲沒有提供給'nextInt'的參數? – Ramy 2011-08-05 02:32:00

+0

@Ramy:閱讀答案。 – missingfaktor 2011-08-05 06:22:22

回答

19

是因爲scala假設您在撥打readInt時正在使用語法a foo b(相當於a.foo(b))。也就是說,它假定while循環是參數readInt(回想一下,每個表達式都有一個類型),因此最後一條語句是一個聲明:

var ntests = read nextInt x 

其中x是你的,而塊。

我必須說,除非這是設計時考慮到這使用DSL具體工作(如演員的a ! b),作爲優先的一個點,我現在已經過a foo b回到使用通常的語法a.foo(b) 。它使事情變得更加清晰,你不會被這種奇怪的東西咬傷!

+4

+1對於最後一段 – ziggystar 2010-02-12 09:38:14

+0

裏面的建議我知道這是一箇舊線程,但是你能明確地在分隔符後面讀nextInt嗎?或者這是一個問題,因爲沒有提供給nextInt的參數? – Ramy 2011-08-05 02:32:55

11

由oxbow_lakes答案附加評論...

var ntests = read nextInt() 

應該解決的事情,你作爲一個替代分號

8

要添加更多一點關於分號推斷,斯卡拉實際上做這個分兩個階段。首先它根據語言規範推斷出一個叫做nl的特殊標記。解析器允許將nl用作語句分隔符以及分號。然而,nl也被允許在其他地方的語法。特別地,一個單一的nl被中綴運算符後允許當從下一行的第一個標記可以啓動表達 - 和while可以啓動的表達,這就是爲什麼它解釋這種方式。不幸的是,雖然while可以啓動一個表達式,但是一個while語句不能用在中綴表達式中,因此是錯誤。就個人而言,解析器工作起來似乎是一個相當古怪的方式,但對於我所瞭解的所有人來說,它背後的理性理由相當合理!

作爲另一種選擇到其他人則建議,把你的[*]線和while線也將解決問題之間的空白換行,因爲只有一個nl被綴運營商後允許的,所以多nl的勢力有不同的解釋通過解析器。