2010-10-18 107 views
2

我的第一個Scala程序和我卡住了。scala覆蓋無

所以基本上我試圖在過去的聲明中覆蓋「last」潛在的None值。

import java.util.Date; 

object TimeUtil { 
    var timerM = Map("" -> new Date().getTime()); 

    def timeit(seq:String, comment:String) { 
     val last = timerM.get(seq) 
     val cur = new Date().getTime() 
     timerM += seq -> cur; 
     println(timerM) 
     if(last == None) return; 

     val past = (last == None) ? 0l : last ; 
     Console.println("Time:" + seq + comment + ":" + (cur - past)/1000 ) 
    } 

    def main(args : Array[String]) { 
     timeit("setup ", "mmm") 
     timeit("setup ", "done") 
    } 
} 
+1

你的意思是取出行'if(last == None)return;'?正如所寫的,當初始化「過去」時,「last」永遠不會是「None」。也就是說,編寫該初始化程序的慣用方法是'val past = last getOrElse 01'。 – 2010-10-18 22:03:06

+0

嗯,有這個編譯器錯誤,我想也許它不夠聰明,推斷該邏輯阻止它爲空。 – smartnut007 2010-10-18 22:08:56

+1

如果適用,你應該總是在你的問題中包含任何錯誤信息(在這種情況下它透明地是) – 2010-10-19 09:27:49

回答

7

你應該嘗試和提煉的問題多一點,但肯定包括你實際的錯誤!

但是,沒有三元操作符(? :)Scala中因此,你可以使用:

if (pred) a else b //instead of pred ? a : b 

這是因爲(幾乎 - 見下文凱文的評論)Scala中的一切都是表達式與返回類型。在Java中,有些事情是語句(沒有類型),這是不正確的。使用scala,最好使用組合,而不是分叉(例如,在您的示例中爲if (expr) return;)。在您的例子三元操作無關反正

val last = timerM.get(seq) 
val cur = System.currentTimeMillis 
timerM += (seq -> cur) 
println(timerM) 
last.foreach{l => println("Time: " + seq + comment + ":" + (l - past)/1000) } 

注意,因爲last不能沒有在這一點上(你剛纔回來,如果它是):所以我會重新寫爲。我的建議是使用明確的類型一段時間,因爲你習慣了Scala。因此,上述將被:

val last: Option[Long] = timerM.get(seq) 
val cur: Long = System.currentTimeMillis 
timerM += (seq -> cur) 
println(timerM) 
last.foreach{l : Long => println("Time: " + seq + comment + ":" + (l - past)/1000) } 

(這似乎在你的評論,你可能會嘗試將Long值賦給last,這將是當然的錯誤,因爲lastOption[Long]型的,不Long

+0

謝謝。假設這也能起作用Console.println(「Hi:」+(cur - last.getOrElse(0L)) – smartnut007 2010-10-18 22:34:50

+2

我也犯了這個錯誤,並非所有Scala中的表達式,變量,類和方法定義都是語句,當編譯器遇到一個以語句結尾的代碼塊時,如果你試圖評估該塊,它會在末尾插入表達式'()' - 因此給出*外觀*這一切都是表達式 – 2010-10-19 00:30:51

+1

你錯了關於轉讓;。它的類型是Unit'的'的表達,但問題依然存在,我會一直更清晰 – 2010-10-19 07:13:19

4

你有一對夫婦的「代碼味道」,在那裏,這表明,一個更好的,更亮澤的設計可能是指日可待:

  • 您正在使用可變變量var而不是val
  • timeit僅由副作用工作,它修改了函數外部的狀態,並且使用相同輸入的連續調用可能會有不同的結果。
  • seq作爲一個變量名稱略有風險,它離標準庫中的(非常常見的&流行)Seq類型太接近。

因此,回到第一原則,如何在更「慣用」的風格下實現相同的結果?最初的設計開始(據我所知):

  • timeit(seq,comment)第一個電話剛指出當前時間
  • seq的println自上次通話所經過的時間相同值的後續調用

基本上,你只是想要一段代碼運行需要多長時間。如果有一種方法可以將「代碼塊」傳遞給函數,那麼也許,也許......也許......幸運的是,斯卡拉能做到這一點,只是用了一個用名字PARAM:

def timeit(block: => Unit) : Long = { 
    val start = System.currentTimeMillis 
    block 
    System.currentTimeMillis - start 
} 

只是檢查出block參數,它看起來有點像不帶參數的函數,這是由名PARAMS是怎麼寫的。函數System.currentTimeMillis - start的最後一個表達式用作返回值。

通過{}包裝參數列表括號()而不是括號,你可以使它看起來像一個內置的控制結構,並使用它像這樣:

val duration = timeit { 
    do stuff here 
    more stuff 
    do other stuff 
} 

println("setup time:" + duration + "ms") 

或者,你可以把println的行爲放回使用timeit功能,但是,使生活困難,如果你以後想重新使用它定時東西,沒有它打印到控制檯:

def timeit(description: String)(block: => Unit) : Unit = { 
    val start = System.currentTimeMillis 
    block 
    val duration System.currentTimeMillis - start 
    println(description + " took " + duration + "ms") 
} 

這是另一招,多參數塊。它允許你使用括號對於第一塊,和括號爲第二:你可以在這個模式中,出現不同程度的複雜性/複雜性

timeit("setup") { 
    do stuff here 
    more stuff 
    do other stuff 
} 
// will print "setup took XXXms" 

當然,還有無數其他的變種,但它應該足以讓你開始...

+0

我有一個沉重的項目,想要介紹一些scala代碼作爲學習體驗。 – smartnut007 2010-10-19 01:49:54

+0

但是,不知道如何從java調用這個。 – smartnut007 2010-10-19 01:55:48

+0

while((line = br.readLine())!= null){ \t \t \t if(line.length()<140)continue; \t \t \t \t \t addDoc(W,線); \t \t \t如果(++ N%100000 == 0) \t \t \t \t TimeUtil.timeit( 「批處理」, 「」 + N/1000); \t \t \t \t \t \t} – smartnut007 2010-10-19 02:00:22