我试图在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)
}

我的实现非常缓慢。使用时间的播种在特定的时间内带来相同的随机数,因此循环一次又一次地迭代。我如何改进我的代码?


当前回答

每次你设置相同的种子,你会得到相同的序列。当然,如果你在一个快速循环中设置时间的种子,你可能会用同一个种子多次调用它。

在你的例子中,当你调用randInt函数直到你有一个不同的值,你在等待时间(由Nano返回)改变。

对于所有伪随机库,您只需设置一次种子,例如在初始化程序时,除非您特别需要重新生成给定的序列(这通常只用于调试和单元测试)。

在此之后,您只需调用Intn来获得下一个随机整数。

将rand.Seed(time.Now(). utc (). unixnano())行从randInt函数移动到main函数的开头,一切都会更快。失去.UTC()调用,因为:

UnixNano返回t作为Unix时间,即自UTC 1970年1月1日以来经过的纳秒数。

还要注意,我认为你可以简化你的字符串构建:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().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)
}

其他回答

如果你的目标只是生成一个随机数刺,那么我认为没有必要用多次函数调用或每次重置种子来复杂化它。

最重要的一步是在实际运行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的原因是它允许简单的字符串格式化。

此外,In rand.Intn(7) Intn作为int返回[0,7)中的非负伪随机数。

为什么这么复杂!

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

这是基于毁灭者的代码但符合我的需要。

它是die 6 (rands int 1 =< i =< 6)

func randomInt (min int , max int  ) int {
    var bytes int
    bytes = min + rand.Intn(max)
    return int(bytes)
}

上面的函数是完全一样的。

我希望这个信息对你有用。

我尝试了下面的程序,每次都看到不同的字符串

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

随着Go 1.20 (Q4 2022),种子随机数生成器的正确方法也可以是…什么都不做。

如果没有调用Seed,生成器将在程序启动时随机播种。

“math/rand:随机种子全局生成器”提案已被接受(2022年10月),并已开始实施:

CL 443058: math/rand:自动播种全局源代码

实现提案#54880,以自动播种全局源代码。

The justification for this not being a breaking change is that any use of the global source in a package's init function or exported API clearly must be valid - that is, if a package changes how much randomness it consumes at init time or in an exported API, that clearly isn't the kind of breaking change that requires issuing a v2 of that package. That kind of per-package change in the position of the global source is indistinguishable from seeding the global source differently. So if the per-package change is valid, so is auto-seeding. And then, of course, auto-seeding means that packages will be far less likely to depend on the specific results of the global source and therefore not break when those kinds of per-package changes happen in the future. Seed(1) can be called in programs that need the old sequence from the global source and want to restore the old behavior. Of course, those programs will still be broken by the per-package changes just described, and it would be better for them to allocate local sources rather than continue to use the global one.


在issue 20661和CL 436955中,还要注意math/rand。Read已弃用:对于几乎所有用例,crypto/rand。读更合适。

如下所示:

我们可以像这样用gosec linter和golanglint-ci 并注意G404代码: goangci -lint run——disable-all——启用gosec

由于golang api的变化,请省略.UTC():

.UnixNano .UTC time.Now()()()——> 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)
}