2011-01-01 19 views
6

È possibile creare una struttura di controllo personalizzata con diversi blocchi di codice, nel modo di before { block1 } then { block2 } finally { block3 }? La domanda riguarda solo la parte zucchero - So che la funzionalità può essere facilmente ottenuta passando i tre blocchi a un metodo, come doInSequence(block1, block2, block3).Scala: strutture di controllo personalizzate con diversi blocchi di codice

Un esempio di vita reale. Per i miei programmi di utilità di test mi piacerebbe creare una struttura come questa:

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

EDIT:

Infine mi si avvicinò con questa soluzione:

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

L'output è:

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

Si basa principalmente sulla risposta di Thomas Lockney, ho appena aggiunto l'oggetto associato di poter import MyTimer._

Grazie a tutti, ragazzi.

risposta

3

Per il tuo esempio, la chiave sarebbe avere il tipo di ritorno di getTime su di esso il metodo after. A seconda del contesto, è possibile utilizzare una singola classe o caratteristica che avvolge entrambi i metodi. Ecco un esempio molto semplice di come potresti avvicinarti:

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

Principio generale. Ovviamente puoi anche prendere i parametri. (. Si noti che il nome dei metodi non hanno alcun significato in questo esempio)

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

Questo è imbarazzante semplice :). Grazie –

8

Se si desidera che questi blocchi a comparire in l'ordine specifico, questa modifica alla risposta di Knut Arne Vedaa avrebbe funzionato:

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

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

... 
1

Non è possibile avere un metodo "diviso", ma è possibile emularlo.

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>