代码之家  ›  专栏  ›  技术社区  ›  smartnut007

scala覆盖无

  •  2
  • smartnut007  · 技术社区  · 15 年前

    我的第一个scala程序被卡住了。

    所以基本上,我试图在过去的声明中将“last”的潜在无值改写为0。

    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 回复  |  直到 15 年前
        1
  •  7
  •   oxbow_lakes    15 年前

    你可能应该试着把这个问题再解决一点,但是 当然 包括您的实际错误!

    但是,有 无三元运算符( ? : 在斯卡拉 因此,您可以使用:

    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 价值到 最后的 ,这当然是一个错误,因为 最后的 属于类型 Option[Long] 不是 )

        2
  •  4
  •   Kevin Wright    15 年前

    这里有两种“代码气味”,这意味着一个更好、更光亮的设计可能就在眼前:

    • 您使用的是可变变量var而不是val
    • TimeIt只通过副作用工作,它修改函数外部的状态,并且具有相同输入的连续调用可以产生不同的结果。
    • seq 作为一个变量名有点冒险,它太接近(非常常见和流行) Seq 从标准库中键入。

    那么,回到第一个原则,在更“惯用”的风格中,如何实现相同的结果呢?从最初的设计开始(据我所知):

    • 第一次呼叫 timeit(seq,comment) 只需记下当前时间
    • 具有相同值的后续调用 SEQ 打印上一次调用后经过的时间

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

    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"
    

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

    推荐文章