Медленная Скала утверждает

Недавно мы профилировали наш код и наткнулись на несколько раздражающих горячих точек. Они в форме

assert(a == b, a + " is not equal to " + b)

Поскольку некоторые из этих утверждений могут быть в коде, называемом огромным количеством раз, когда строка concat начинает суммироваться. assert определяется как:

def assert(assumption : Boolean, message : Any) = ....

почему не определяется как:

def assert(assumption : Boolean, message : => Any) = ....

Таким образом это оценило бы лениво. Учитывая, что это не определено таким образом, существует ли встроенный способ вызова assert с параметром сообщения, который оценивается лениво?

Спасибо

4 ответа

Решение

Ленивая оценка также имеет некоторые накладные расходы для созданного объекта функции. Если ваш объект сообщения уже полностью создан (статическое сообщение), эти издержки не нужны.

Подходящий метод для вашего варианта использования будет sprintf-style:

assert(a == b,  "%s is not equal to %s", a, b)

Пока есть специализированная функция

assert(Boolean, String, Any, Any)

эта реализация не имеет накладных расходов или стоимости массива var args

assert(Boolean, String, Any*)

для общего случая.

Реализация toString будет оценена лениво, но не читабельно:

assert(a == b, new { override def toString =  a + " is not equal to " + b })

Это по имени, я поменял его больше года назад.

http://www.scala-lang.org/node/825

Текущий Predef:

@elidable(ASSERTION)
def assert(assertion: Boolean, message: => Any) {
  if (!assertion)
    throw new java.lang.AssertionError("assertion failed: "+ message)
}

Ответ Томаса великолепен, но в случае, если вам нравится идея последнего ответа, но не нравится нечитаемость, вы можете обойти ее:

object LazyS {
  def apply(f: => String): AnyRef = new {
    override def toString = f
  }
}

Пример:

object KnightSpeak {
  override def toString = { println("Turned into a string") ; "Ni" }
}

scala> assert(true != false , LazyS("I say " + KnightSpeak))

scala> println( LazyS("I say " + KnightSpeak) )
Turned into a string
I say Ni

Пытаться: assert( a==b, "%s is not equals to %s".format(a,b))Формат должен вызываться только тогда, когда assert требуется строка. Формат добавляется в RichString через неявный.

Другие вопросы по тегам