Скала, перекрывающая Нет - PullRequest
2 голосов
/ 19 октября 2010

Моя первая программа Scala, и я застрял.

Поэтому в основном я пытаюсь переопределить потенциальное значение None "last" в 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 ]

7 голосов
/ 19 октября 2010

Вы, вероятно, должны попытаться объяснить проблему немного больше, но , конечно, включает вашу фактическую ошибку!

Однако в 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 не может быть 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)

4 голосов
/ 19 октября 2010

У вас есть пара «запахов кода», которые предполагают, что лучший, более блестящий дизайн, вероятно, уже не за горами:

  • Вы используете изменяемую переменную, var вместо val
  • время работает исключительно за счет побочных эффектов, оно изменяет состояние вне функции, и последующие вызовы с одним и тем же входом могут иметь разные результаты.
  • 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"

Конечно, есть миллион других вариантов, которые вы можете сделать по этому шаблону, с различной степенью сложности / сложности, но этого должно быть достаточно, чтобы вы начали ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...