scala overriding无

时间:2010-10-18 21:59:54

标签: scala

我的第一个Scala计划,我被困住了。

所以基本上我试图在过去的声明中将“last”的潜在None值覆盖为0l。

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")
    }
}

2 个答案:

答案 0 :(得分:7)

您应该尝试再解决问题,但当然包括您的实际错误!

但是,Scala 中没有没有三元运算符(? :),所以您可以使用:

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

这是因为(几乎 - 请参阅下面的Kevin的评论)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不能为None(如果是,则刚刚返回)。我的建议是在短时间内使用显式类型,因为你习惯了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,这当然是错误的,因为last属于类型Option[Long],而非Long

答案 1 :(得分:4)

你有几个“代码味道”,这表明更好,更闪亮的设计可能就在附近:

  • 你正在使用一个可变变量var而不是val
  • timeit仅由副作用工作,它修改函数外的状态,并且使用相同输入的连续调用可能会产生不同的结果。
  • seq作为变量名称风险稍大,它与标准库中的(非常常见和流行的)Seq类型相距太近。

因此,回到第一原则,如何以更“惯用”的方式实现相同的结果?从原始设计开始(据我所知):

  • 第一次拨打timeit(seq,comment)只是记下当前时间
  • 具有相同值seq的后续通话打印上次通话后经过的时间

基本上,您只想计算一段代码运行的时间。如果有一种方法可以将“代码块”传递给函数,那么也许,只是可能......幸运的是,scala可以做到这一点,只需使用一个名字参数:

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

只需查看block参数,它看起来有点像没有参数的函数,这就是编写按名称参数的方式。函数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"

当然,你可以在这个模式上做出一百万个其他变种,具有不同程度的复杂性/复杂性,但它应该足以让你开始......