我想做什么:
根据字符串的内容(例如a1b2c3d4e5
),我想生成一堆“可重复的”随机事件。在Golang中生成可重复的随机数很容易 - 您只需使用rand.Seed()函数为随机数生成器播种特定数字,然后就完成了。
但是,rand.Seed()函数将int64作为参数。所以我需要以某种方式将字符串转换为int64。
我已经尝试过了:
我的第一个想法是使用base64对字符串进行编码,然后将字节序列转换为int64。但是,通过一些基本的测试,似乎只支持大约7长度的字符串。添加第8个字符后,数字保持不变。
我想这里的根本问题是字符串值可能比int64值更多。
那么某种哈希函数呢?我知道的大多数哈希函数都返回一个字节序列;我需要某种返回int64的哈希函数。也许这种方法也被误导了?
答案 0 :(得分:4)
字符串的哈希就可以了。
您可以使用:
示例代码(playground link):
package main
import (
"crypto/md5"
"encoding/binary"
"fmt"
"io"
"math/rand"
)
func main() {
h := md5.New()
io.WriteString(h, "And Leon's getting larger!")
var seed uint64 = binary.BigEndian.Uint64(h.Sum(nil))
fmt.Println(seed)
rand.Seed(int64(seed))
fmt.Println(rand.Int())
}
打印:
2458341265858962012
792667671
注意:md5只是一个例子。您可以使用任何生成至少8个字节的哈希。例如:sha256。只需将md5.New()
替换为sha256.New()
(以及导入)即可。
您可以找到一个很好的哈希示例列表here。
还有一个关于警告的重要信息:这根本不涉及加密应用程序。我假设这是用于非加密目的的用户提供的种子(例如:游戏种子)。
答案 1 :(得分:2)
使用哈希函数是一个很好的方向。并且要生成一个适合int64
的值,只需获取哈希值的前8个字节。
对于良好的散列函数,散列结果的每个字节(或者更确切地说每个位)取决于所有输入字节,因此前8个字节不会得到"卡住"在一定的输入长度之后。
要将8个字节的切片转换为int64
值,您可以使用encoding/binary
包。
例如:
digest := ... // calculate digest
seed := int64(binary.BigEndian.Uint64(digest[:8]))
也可以省略对摘要值digest[:8]
进行切片,因为BigEndian.Uint64()
调用只会读取前8个字节。
答案 2 :(得分:0)
你可以试试这个。您可以通过使用时间生成不同的种子来为生成随机事件提供不同的序列。
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)
}