2011-01-01 6 views
6

Ist es möglich, eine benutzerdefinierte Kontrollstruktur mit mehreren Codeblöcken in der Art von before { block1 } then { block2 } finally { block3 } zu erstellen? Die Frage betrifft nur den Zuckerteil - ich weiß, dass die Funktionalität leicht erreicht werden kann, indem man die drei Blöcke an eine Methode wie doInSequence(block1, block2, block3) übergibt.Scala: Benutzerdefinierte Kontrollstrukturen mit mehreren Codeblöcken

Ein Beispiel aus dem wirklichen Leben. Für meine Tests Dienstprogramme würde Ich mag eine Struktur wie diese erstellen:

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

EDIT:

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) 
} 

Der Ausgang ist:

Schließlich ich mit dieser Lösung kam

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

Es basiert meist auf der Antwort von Thomas Lockney, Ich habe gerade das begleitende Objekt hinzugefügt, um import MyTimer._

Vielen Dank, Jungs.

Antwort

3

Für Ihr gegebenes Beispiel wäre der Schlüssel der Rückgabetyp getTime haben die after Methode darauf. Abhängig vom Kontext können Sie eine einzelne Klasse oder Eigenschaft verwenden, die beide Methoden umschließt. Hier ist ein sehr vereinfachtes Beispiel für die Vorgehensweise:

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 
    } 
} 
13

Allgemeines Prinzip. Sie können natürlich auch Parameter nehmen. (. Beachten Sie, dass der Name der Verfahren in diesem Beispiel keine Bedeutung haben)

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 = [email protected] 
+0

Das ist peinlich einfach :). Vielen Dank –

8

Wenn Sie diese Blöcke wollen in der bestimmten Reihenfolge erscheinen, diese Änderung zu Knut Arne Vedaa Antwort funktionieren würde:

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

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

... 
1

Es ist nicht möglich, eine "Split" -Methode zu verwenden, aber Sie können sie emulieren.

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> 
Verwandte Themen