【问题标题】:Is there a brief syntax for executing a block n times in Scala?在 Scala 中执行 n 次块是否有简短的语法?
【发布时间】:2011-02-20 00:22:42
【问题描述】:

当我想重复执行 n 次时,我发现自己正在编写这样的代码:

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

我正在寻找像这样的更短的语法:

n.times(doSomething())

Scala 中是否已经存在类似的东西?

编辑

我考虑过使用 Range 的 foreach() 方法,但是该块需要采用它从未使用过的参数。

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

【问题讨论】:

  • 以要求您的代码读者理解您的个人 DSL 为代价来节省 5-6 个输入字符?我认为这是一个错误。
  • 你可以最小化被忽略的东西:1 to n foreach(_ =&gt; doSomething())
  • @Paul 真的不应该是个人 DSL。一种在数字上调用 times() 的方法在其他语言中很常见。
  • 您为什么要多次致电doSomething()?它总是会返回相同的Unit。 ;)
  • 所以这个问题的简短回答是:不。

标签: scala


【解决方案1】:

您可以使用 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

【讨论】:

  • 我希望在 RichInt 中添加“时间”。
  • 它实际上是添加的 (lampsvn.epfl.ch/trac/scala/changeset/18599/scala/trunk/src/…),但不久后被删除 (lampsvn.epfl.ch/trac/scala/changeset/18648/scala/trunk/src/…)。 Quoth extempore:“那是最好的时代……那是时代的逆转……”。向标准库添加东西可能会破坏现有代码,必须相当谨慎地进行。
  • 这真的很有趣。 2.8 还没有破坏向后兼容性吗?我认为在那种情况下,有人错过了添加这种方法的机会。它归结为人们一遍又一遍地编写该代码,因为它有一个用例。您可以将其命名为不同的名称,例如“5次迭代x”或“5次重复x”。
  • Joa:你可以用谷歌搜索很多讨论,包括这个精确的想法。
【解决方案2】:

Range 类上有一个 foreach 方法,我认为这正是您所需要的。例如,这个:

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

生产

0
1
2
3
4
5

【讨论】:

  • 或者:7 to 11 foreach { println(_) }
  • 0 to 5 foreach println 看起来更干净。
【解决方案3】:

scalaz 5:

doSomething.replicateM[List](n)

scalaz 6:

n times doSomething

这对大多数类型都有效(更准确地说,对于每个幺半群):

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!

您也可以说doSomething replicateM_ 5,这仅在您的doSomething 是惯用值时才有效(请参阅Applicative)。它具有更好的类型安全性,因为您可以这样做:

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

但不是这个:

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

让我看看你在 Ruby 中实现了这一点。

【讨论】:

  • 非常酷...我不知道 scalaz 有一个 IO monad...在实践中你觉得这值得在 scala 中付出努力吗?
  • 看起来5 times 10 任意选择使用 (0,+) 幺半群进行排序,这是有道理的,因为在英语中我们将“5 乘以 10”解释为 50... 你能覆盖吗它使用 (1,*) 并求幂?
  • pelotom:要获得 2^24,您可以写:24 times (2 ∏)
  • 这些天我在做一些 IO,我在 monad 中做。
  • @Apocalisp 我并不总是做 IO,但是当我做的时候,我会在一个 monad 中做
【解决方案4】:

我不知道图书馆里有什么。您可以定义一个实用程序隐式转换和可以根据需要导入的类。

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 刚刚发布了一个类似的答案......

【讨论】:

    【解决方案5】:

    可以这么简单:

    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
    

    【讨论】:

      【解决方案6】:
      def times(f: => Unit)(cnt:Int) :Unit = {
        List.fill(cnt){f}
      }
      

      【讨论】:

      • 虽然代码可能会解决问题,但一个好的答案还应该解释代码的什么以及它如何提供帮助。
      猜你喜欢
      • 1970-01-01
      • 2011-07-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 2013-08-06
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多