在函数getRandomString
下面,从字符列表中生成一个随机字符串:
def genRandomInt(lb: Int, ub: Int) = {
val rnd = new scala.util.Random
lb + rnd.nextInt(ub)
}
def getRandomString(validChars: List[Char]) = {
val size = validChars.size
val random = new scala.util.Random
val stringBuilder = new StringBuilder
val rnd = genRandomInt(0, size)
val sb = new StringBuilder
for (i <- 0 to size - 1) {
val rnd = genRandomInt(0, size)
sb.append(validChars(rnd))
}
sb.toString
} //> getRandomString: (validChars: List[Char])String
val rs = getRandomString(('a' to 'j').toList)
//> rs : String = aghdjjhjge
getRandomString
是纯函数的一个例子,因为它不会修改状态吗?
答案 0 :(得分:8)
不,因为它实际上确实修改了状态。 new scala.util.Random
最终调用new java.util.Random
,它访问并修改名为AtomicLong
的静态(即全局)可变seedUniquifier
。因此,如果多次调用此方法,则结果将发生变化。
这是一个很好的例子,说明无辜的看似方法如何隐藏对全局可变状态的访问,这在Haskell等更严格的函数式语言中是被禁止的(尽管这种方法有其自身的问题)。
答案 1 :(得分:1)
不,因为new scala.util.Random().nextInt ...
每次都会返回不同的内容,这是由Imm。
然而,您可以简单地传入一个种子然后它将是一个纯函数,因为它每次都会返回相同的随机字符串。您可以将种子添加为参数,或者只是将其固定在随机字符串方法中。
最后,我注意到您已经编写了大量代码来生成随机字符串。我建议你看一下ScalaCheck,它有很多有用的函数来生成随机的东西(用于单元测试),String
是开箱即用的。
如果您不想加入某个库,您仍然可以使该代码更加简洁:
def randomString(fromChars: List[Char], length: Int): String = {
val rand = new Random(1234) // Now it's pure functional because the seed is fixed
val fromCharsSize = fromChars.size // to save us repeatedly counting
List.fill(length)(fromChars(rand.nextInt(fromCharsSize))).mkString
}
观察它每次返回相同的值
scala> randomString("asdf".toList, 10)
res0: String = dsfafssdsa
scala> randomString("asdf".toList, 10)
res1: String = dsfafssdsa