游戲社交部分往往需要邀請(qǐng)碼。以下是我的實(shí)現(xiàn)。供參考。其中有一些依賴的框架的特定代碼,但不影響理解邏輯。值得強(qiáng)調(diào)的點(diǎn)是,去掉了幾個(gè)在顯示時(shí)容易混淆的字符。
import "math/rand"
const (
invitationCodeMinLength = 6
invitationCodeMaxLength = 10
// 排除的字符包括:數(shù)字0和1,大寫(xiě)字母D、I和O,小寫(xiě)字母l和o
invitationCodeChars = `23456789ABCEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz`
)
func GenInvitationCode() (string, err2.AppError) {
for i := invitationCodeMinLength; i <= invitationCodeMaxLength; i++ {
for j := 0; j < 3; j++ {
code := randCodeWithLen(i)
u, err := isUnique(code)
if err != nil {
return "", err
}
if u {
return code, nil
}
}
}
return "", err2.AppErrorFromProtoEnum(msg.ErrorCode_SERVICE_INTERNAL_ERROR)
}
func randCodeWithLen(length int) string {
cs := make([]byte, 0, length)
for i := 0; i < length; i++ {
n := rand.Intn(len(invitationCodeChars))
c := invitationCodeChars[n]
cs = append(cs, c)
}
return string(cs)
}
func isUnique(code string) (bool, err2.AppError) {
// 查詢數(shù)據(jù)庫(kù)
}
下面是單元測(cè)試。
func Test_randCodeWithLen_dup(t *testing.T) {
a := assert.New(t)
const count int = 1e8
codes := make(map[string]struct{}, count)
var dupCount int
for j := 0; j < count; j++ {
var dup bool
for i := invitationCodeMinLength; i <= invitationCodeMaxLength; i++ {
code := randCodeWithLen(i)
a.Equal(i, len(code))
if _, ok := codes[code]; ok {
dup = true
} else {
dup = false
codes[code] = struct{}{}
break
}
}
if dup {
dupCount++
}
}
t.Logf("count=%d, dupCount=%d", count, dupCount)
}
一億次生成,重復(fù)次數(shù)為0??梢哉f(shuō)明重復(fù)的概率很低。
建表腳本如下。
CREATE TABLE IF NOT EXISTS `invitation_code` (
`code` VARCHAR(10) NOT NULL,
`uid` BIGINT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;