Скала:пользовательские структуры управления с несколькими блоками кода
-
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>