我试图在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)
}
我的实现非常缓慢。使用时间的播种在特定的时间内带来相同的随机数,因此循环一次又一次地迭代。我如何改进我的代码?
只是为了子孙后代:有时使用初始字符集字符串生成随机字符串更可取。如果字符串应该由人类手动输入,这是有用的;排除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
只是为了子孙后代:有时使用初始字符集字符串生成随机字符串更可取。如果字符串应该由人类手动输入,这是有用的;排除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
随着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
我尝试了下面的程序,每次都看到不同的字符串
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