我想在Go中生成一个随机字符串,这是我到目前为止编写的代码:
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println(randomString(10))
}
func randomString(l int) string {
var result bytes.Buffer
var temp string
for i := 0; i < l; {
if string(randInt(65, 90)) != temp {
temp = string(randInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
func randInt(min int, max int) int {
rand.Seed(time.Now().UTC().UnixNano())
return min + rand.Intn(max-min)
}
我的实施很慢。使用time
播种会在一定时间内带来相同的随机数,因此循环会一次又一次地迭代。如何改进我的代码?
答案 0 :(得分:201)
每次设置相同的种子时,都会得到相同的序列。所以当然如果你将种子设置为快速循环中的时间,你可能会多次使用相同的种子调用它。
在你的情况下,当你调用randInt
函数直到你有不同的值时,你正在等待时间(由Nano返回)来改变。
As for all pseudo-random libraries,你必须只设置种子一次,例如在初始化你的程序时,除非你特别需要重现给定的序列(通常只进行调试和单元测试)。
之后,您只需调用Intn
即可获得下一个随机整数。
将rand.Seed(time.Now().UTC().UnixNano())
行从randInt函数移动到main的开头,一切都会更快。
另请注意,我认为您可以简化字符串构建:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UTC().UnixNano())
fmt.Println(randomString(10))
}
func randomString(l int) string {
bytes := make([]byte, l)
for i := 0; i < l; i++ {
bytes[i] = byte(randInt(65, 90))
}
return string(bytes)
}
func randInt(min int, max int) int {
return min + rand.Intn(max-min)
}
答案 1 :(得分:15)
只是为了后代而抛弃它:有时候最好使用初始字符集字符串生成随机字符串。如果字符串应该由人手动输入,这很有用;排除0,O,1和l可以帮助减少用户错误。
var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
// generates a random string of fixed size
func srand(size int) string {
buf := make([]byte, size)
for i := 0; i < size; i++ {
buf[i] = alpha[rand.Intn(len(alpha))]
}
return string(buf)
}
我通常将种子设置在init()
块内。他们在此处记录:http://golang.org/doc/effective_go.html#init
答案 2 :(得分:12)
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed( time.Now().UnixNano())
var bytes int
for i:= 0 ; i < 10 ; i++{
bytes = rand.Intn(6)+1
fmt.Println(bytes)
}
//fmt.Println(time.Now().UnixNano())
}
这是基于dystroy的代码,但符合我的需要。
它死了六次(rands int 1 =< i =< 6
)
func randomInt (min int , max int ) int {
var bytes int
bytes = min + rand.Intn(max)
return int(bytes)
}
上述功能完全相同。
我希望这些信息有用。
答案 3 :(得分:10)
我不明白为什么人们播种时间价值。以我的经验,这从来不是一个好主意。例如,虽然系统时钟可能以纳秒为单位表示,但系统的时钟精度不是纳秒。
This program不应在Go游乐场上运行,但如果在计算机上运行,则可以粗略估算出您可以期望的精度类型。我看到约1000000 ns的增量,所以1毫秒的增量。那是20位未使用的熵。 一直以来,高位基本上都是恒定的。
这对您重要的程度会有所不同,但您只需使用crypto/rand.Read
作为种子的来源,就可以避免基于时钟的种子值的陷阱。它将为您提供您可能会在随机数中寻找的不确定性质量(即使实际实现本身仅限于一组不同且确定性的随机序列)。
import (
crypto_rand "crypto/rand"
"encoding/binary"
math_rand "math/rand"
)
func init() {
var b [8]byte
_, err := crypto_rand.Read(b[:])
if err != nil {
panic("cannot seed math/rand package with cryptographically secure random number generator")
}
math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:])))
}
作为旁注,但与您的问题有关。您可以使用此方法创建自己的rand.Source
,以避免使用锁来保护源代码的开销。 rand
软件包实用程序函数很方便,但它们也使用幕后的锁来防止同时使用源。如果不需要,可以通过创建自己的Source
并以非并行方式使用它来避免这种情况。无论如何,您不应该在迭代之间重新使用随机数生成器,它永远不会被设计为以这种方式使用。
答案 4 :(得分:1)
我尝试了下面的程序,每次都看到不同的字符串
package main
import (
"fmt"
"math/rand"
"time"
)
func RandomString(count int){
rand.Seed(time.Now().UTC().UnixNano())
for(count > 0 ){
x := Random(65,91)
fmt.Printf("%c",x)
count--;
}
}
func Random(min, max int) (int){
return min+rand.Intn(max-min)
}
func main() {
RandomString(12)
}
控制台上的输出是
D:\james\work\gox>go run rand.go
JFBYKAPEBCRC
D:\james\work\gox>go run rand.go
VDUEBIIDFQIB
D:\james\work\gox>go run rand.go
VJYDQPVGRPXM
答案 5 :(得分:0)
这是纳秒,两次获得相同种子的几率是多少 无论如何,感谢您的帮助,这是基于所有输入的最终解决方案。
package main
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
// generates a random string
func srand(min, max int, readable bool) string {
var length int
var char string
if min < max {
length = min + rand.Intn(max-min)
} else {
length = min
}
if readable == false {
char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
} else {
char = "ABCDEFHJLMNQRTUVWXYZabcefghijkmnopqrtuvwxyz23479"
}
buf := make([]byte, length)
for i := 0; i < length; i++ {
buf[i] = char[rand.Intn(len(char)-1)]
}
return string(buf)
}
// For testing only
func main() {
println(srand(5, 5, true))
println(srand(5, 5, true))
println(srand(5, 5, true))
println(srand(5, 5, false))
println(srand(5, 7, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 4, true))
println(srand(5, 400, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
}
答案 6 :(得分:0)
如果您的目的只是生成一个随机数的字符串,那么我认为没有必要将它与多个函数调用复杂化或每次都重置种子。
最重要的步骤是在实际运行rand.Init(x)
之前调用一次种子函数。 Seed使用提供的种子值将默认Source初始化为确定性状态。因此,建议在实际函数调用伪随机数生成器之前先调用它。
下面是创建随机数字符串的示例代码
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
rand.Seed(time.Now().UnixNano())
var s string
for i:=0;i<10;i++{
s+=fmt.Sprintf("%d ",rand.Intn(7))
}
fmt.Printf(s)
}
我使用Sprintf的原因是因为它允许简单的字符串格式。
此外,在rand.Intn(7)
中,Intn以int形式返回[0,7)中的非负伪随机数。
答案 7 :(得分:0)
由于golang api的更改而导致的小更新,请省略.UTC():
time.Now()。 UTC() .UnixNano()-> time.Now()。UnixNano()
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomInt(100, 1000))
}
func randInt(min int, max int) int {
return min + rand.Intn(max-min)
}
答案 8 :(得分:0)
@ [DenysSéguret]已正确发布。但就我而言,我每次都需要新的种子,因此代码如下;
如果您需要快速功能。我这样使用。
func RandInt(min, max int) int {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return r.Intn(max-min) + min
}
func RandFloat(min, max float64) float64 {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return min + r.Float64()*(max-min)
}
答案 9 :(得分:0)
每次在 for 循环内调用 randint() 方法时,都会设置不同的种子,并根据 时间 生成序列。但是由于循环在您的计算机中在短时间内运行得很快,种子几乎相同,并且由于时间,生成了与过去非常相似的序列。所以在 randint() 方法之外设置种子就足够了。
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
var r = rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
func main() {
fmt.Println(randomString(10))
}
func randomString(l int) string {
var result bytes.Buffer
var temp string
for i := 0; i < l; {
if string(randInt(65, 90)) != temp {
temp = string(randInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
func randInt(min int, max int) int {
return min + r.Intn(max-min)
}