Domanda C'è una sintassi breve per eseguire un blocco n volte in Scala?


Mi trovo a scrivere un codice come questo quando voglio ripetere qualche esecuzione n volte:

for (i <- 1 to n) { doSomething() }

Sto cercando una sintassi più breve come questa:

n.times(doSomething())

Esiste già qualcosa di simile in Scala?

MODIFICARE

Ho pensato di usare il metodo foreach () di Range, ma poi il blocco ha bisogno di prendere un parametro che non usa mai.

(1 to n).foreach(ignored => doSomething())

44
2018-05-16 03:56


origine


risposte:


Si potrebbe facilmente definire uno usando il pattern Pimp My Library.

scala> implicit def intWithTimes(n: Int) = new {        
     |   def times(f: => Unit) = 1 to n foreach {_ => f}
     | }
intWithTimes: (n: Int)java.lang.Object{def times(f: => Unit): Unit}

scala> 5 times {
     |   println("Hello World")
     | }
Hello World
Hello World
Hello World
Hello World
Hello World

48
2018-05-16 04:59



La classe Range ha un metodo foreach su di esso che penso sia proprio quello di cui hai bisogno. Ad esempio, questo:

 0.to(5).foreach(println(_))

prodotta

0
  1
  2
  3
  4
  5


31
2018-05-16 04:06



Con scalaz 5:

doSomething.replicateM[List](n)

Con scalaz 6:

n times doSomething

E funziona come ci si aspetterebbe con la maggior parte dei tipi (più precisamente, per ogni monoide):

scala> import scalaz._; import Scalaz._; import effects._;
import scalaz._
import Scalaz._
import effects._

scala> 5 times "foo"
res0: java.lang.String = foofoofoofoofoo

scala> 5 times List(1,2)
res1: List[Int] = List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)

scala> 5 times 10
res2: Int = 50

scala> 5 times ((x: Int) => x + 1).endo
res3: scalaz.Endo[Int] = <function1>

scala> res3(10)
res4: Int = 15

scala> 5 times putStrLn("Hello, World!")
res5: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon$2@36659c23

scala> res5.unsafePerformIO
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!

Potresti anche dire doSomething replicateM_ 5 che funziona solo se il tuo doSomething è un valore idiomatico (vedi Applicative). Ha una migliore sicurezza dei caratteri, dal momento che puoi fare questo:

scala> putStrLn("Foo") replicateM_ 5
res6: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon$2@8fe8ee7

ma non questo:

scala> { System.exit(0) } replicateM_ 5
<console>:15: error: value replicateM_ is not a member of Unit

Lascia che ti veda tirare fuori quello in Ruby.


21
2018-03-31 14:23



Non sono a conoscenza di nulla nella libreria. È possibile definire una conversione e una classe implicite dell'utilità che è possibile importare secondo necessità.

class TimesRepeat(n:Int) {
  def timesRepeat(block: => Unit): Unit = (1 to n) foreach { i => block }
}
object TimesRepeat {
  implicit def toTimesRepeat(n:Int) = new TimesRepeat(n)
}

import TimesRepeat._

3.timesRepeat(println("foo"))

Rahul ha appena postato una risposta simile mentre stavo scrivendo questo ...


5
2018-05-16 05:01



Può essere semplice come questo:

scala> def times(n:Int)( code: => Unit ) {
          for (i <- 1 to n) code
       }
times: (n: Int)(code: => Unit)Unit

scala> times(5) {println("here")}
here
here
here
here
here

2
2018-03-31 19:23