Скала:пользовательские структуры управления с несколькими блоками кода

StackOverflow https://stackoverflow.com/questions/4573587

  •  14-10-2019
  •  | 
  •  

Вопрос

Можно ли создать собственную структуру управления с несколькими блоками кода, наподобие before { block1 } then { block2 } finally { block3 }?Вопрос касается только сахарной части - я знаю, что эту функциональность можно легко достичь, передав три блока в метод, например doInSequence(block1, block2, block3).

Пример из реальной жизни.Для моих утилит тестирования я хотел бы создать такую ​​структуру:

getTime(1000) {
  // Stuff I want to repeat 1000 times.
} after { (n, t) => 
  println("Average time: " + t / n)
}

РЕДАКТИРОВАТЬ:

Наконец я придумал такое решение:

object MyTimer {
  def getTime(count: Int)(action : => Unit): MyTimer = {
    val start = System.currentTimeMillis()
    for(i <- 1 to count) { action }
    val time = System.currentTimeMillis() - start
    new MyTimer(count, time)
  }
}

class MyTimer(val count: Int, val time: Long) {
  def after(action: (Int, Long) => Unit) = {
    action(count, time)
  }
}

// Test
import MyTimer._

var i = 1
getTime(100) {
  println(i)
  i += 1
  Thread.sleep(10)
} after { (n, t) => 
  println("Average time: " + t.toDouble / n)
}

Результат:

1
2
3
...
99
100
Average time: 10.23

В основном это основано на ответе Томас Локни, я просто добавил объект-компаньон, чтобы иметь возможность import MyTimer._

Спасибо всем, ребята.

Это было полезно?

Решение

Для вашего примера ключевым моментом будет наличие возвращаемого типа getTime иметь after метод на нем.В зависимости от контекста вы можете использовать один класс или черту, охватывающую оба метода.Вот очень упрощенный пример того, как вы можете подойти к этому:

class Example() {
  def getTime(x: Int)(f : => Unit): Example = {
    for(i <- 0 to x) {
      // do some stuff
      f
      // do some more stuff
    }
    // calculate your average
    this
  }
  def after(f: (Int, Double) => Unit) = {
    // do more stuff
  }
}

Другие советы

Основной принцип.Конечно, вы также можете использовать параметры.(Обратите внимание, что названия методов не имеют значения в этом примере.)

scala> class Foo {
     | def before(f: => Unit) = { f; this }
     | def then(f: => Unit) = { f; this }
     | def after(f: => Unit) = { f; this }
     | }
defined class Foo

scala> object Foo { def apply() = new Foo }
defined module Foo

scala> Foo() before { println("before...") } then {
     | println("then...") } after {
     | println("after...") }
before...
then...
after...
res12: Foo = Foo@1f16e6e

Если вы хотите, чтобы эти блоки отображались в определенном порядке, это изменение в ответе Кнута Арне Ведаа будет работать:

class Foo1 {
  def before(f: => Unit) = { f; new Foo2 }
}

class Foo2 {
  def then(f: => Unit) = { f; new Foo3 }
}

...

Невозможно иметь метод «разделения», но вы можете его эмулировать.

class Finally(b: => Unit, t: => Unit) {
    def `finally`(f: => Unit) = {
        b
        try { t } finally { f }
    }
}

class Then(b: => Unit) {
    def `then`(t: => Unit): Finally = new Finally(b, t)
}

def before(b: => Unit): Then = new Then(b)

scala> before { println("Before") } `then` { 2 / 0 } `finally` { println("finally") }
Before
finally
[line4.apply$mcV$sp] (<console>:9)
(access lastException for the full trace)
scala>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top