Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Go math/rand/v2 包详解

概述

math/rand/v2 包是 Go 1.22 引入的新版伪随机数生成器包。相比旧的 math/rand 包,v2 版本提供了更好的 API 设计、新的随机源实现(PCG 和 ChaCha8)、以及更多功能。适用于模拟、测试等非安全敏感场景。

重要说明

  • ⚠️ 不应用于安全敏感场景(如密码、令牌)
  • ✓ Go 1.22+ 引入的新版本 API
  • ✓ 提供 PCG 和 ChaCha8 两种随机源
  • ✓ 包级别函数是线程安全的
  • Rand 类型不是线程安全的,需要加锁
  • ✓ 自动种子化,无需手动调用 Seed

包导入

import "math/rand/v2"

基本使用

1. 生成随机整数

package main

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

func main() {
    // 生成随机整数
    fmt.Printf("随机 int: %d\n", rand.Int())
    fmt.Printf("随机 int64: %d\n", rand.Int64())
    fmt.Printf("随机 int32: %d\n", rand.Int32())
    
    // 生成范围内的随机数
    fmt.Printf("0-99: %d\n", rand.IntN(100))
    fmt.Printf("0-9: %d\n", rand.Int32N(10))
    fmt.Printf("0-999: %d\n", rand.Int64N(1000))
}

2. 生成随机浮点数

package main

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

func main() {
    // 生成随机浮点数
    fmt.Printf("float64: %f\n", rand.Float64())
    fmt.Printf("float32: %f\n", rand.Float32())
}

3. 使用 PCG 随机源

package main

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

func main() {
    // 创建 PCG 随机源
    pcg := rand.NewPCG(42, 123)
    r := rand.New(pcg)
    
    // 使用 Rand 对象
    fmt.Printf("随机数 1: %d\n", r.IntN(100))
    fmt.Printf("随机数 2: %d\n", r.IntN(100))
    fmt.Printf("随机数 3: %d\n", r.IntN(100))
}

一、包级别函数

ExpFloat64

定义:

func ExpFloat64() float64

说明:

  • 功能:返回指数分布的 float64
  • 返回值float64 - 范围 (0, +MaxFloat64]
  • 分布:速率参数 λ=1,均值=1
  • 用途:模拟事件间隔时间

示例:

package main

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

func main() {
    // 生成指数分布随机数
    for i := 0; i < 5; i++ {
        fmt.Printf("%.4f\n", rand.ExpFloat64())
    }
    
    // 调整速率参数
    rate := 2.0
    sample := rand.ExpFloat64() / rate
    fmt.Printf("速率=%.2f 的样本:%.4f\n", rate, sample)
}

Float32

定义:

func Float32() float32

说明:

  • 功能:返回 [0.0, 1.0) 范围内的随机 float32
  • 返回值float32

示例:

package main

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

func main() {
    // 生成 5 个随机 float32
    for i := 0; i < 5; i++ {
        fmt.Printf("%.4f\n", rand.Float32())
    }
}

Float64

定义:

func Float64() float64

说明:

  • 功能:返回 [0.0, 1.0) 范围内的随机 float64
  • 返回值float64

示例:

package main

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

func main() {
    // 生成 5 个随机 float64
    for i := 0; i < 5; i++ {
        fmt.Printf("%.6f\n", rand.Float64())
    }
}

Int

定义:

func Int() int

说明:

  • 功能:返回非负随机整数
  • 返回值int - 范围 [0, MaxInt]

示例:

package main

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

func main() {
    // 生成 5 个随机整数
    for i := 0; i < 5; i++ {
        fmt.Printf("%d\n", rand.Int())
    }
}

Int32

定义:

func Int32() int32

说明:

  • 功能:返回非负 32 位随机整数
  • 返回值int32 - 范围 [0, 2^32-1]
  • 注意:v2 版本使用 Int32 替代了 v1 的 Int31

示例:

package main

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

func main() {
    fmt.Printf("随机 int32: %d\n", rand.Int32())
    fmt.Printf("最大值:2^32-1 = %d\n", int32(^uint32(0)>>1))
}

Int32N

定义:

func Int32N(n int32) int32

说明:

  • 功能:返回 [0, n) 范围内的随机 int32
  • 参数n - 上界(必须 > 0)
  • 返回值int32
  • 注意:n <= 0 时会 panic
  • 变化:v2 版本使用 Int32N 替代了 v1 的 Int31n

示例:

package main

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

func main() {
    // 模拟骰子
    fmt.Printf("骰子:%d\n", rand.Int32N(6)+1)
    
    // 生成 10 个 0-99 的随机数
    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", rand.Int32N(100))
    }
}

Int64

定义:

func Int64() int64

说明:

  • 功能:返回非负 64 位随机整数
  • 返回值int64 - 范围 [0, 2^63-1]
  • 注意:v2 版本使用 Int64 替代了 v1 的 Int63

示例:

package main

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

func main() {
    fmt.Printf("随机 int64: %d\n", rand.Int64())
}

Int64N

定义:

func Int64N(n int64) int64

说明:

  • 功能:返回 [0, n) 范围内的随机 int64
  • 参数n - 上界(必须 > 0)
  • 返回值int64
  • 注意:n <= 0 时会 panic
  • 变化:v2 版本使用 Int64N 替代了 v1 的 Int63n

示例:

package main

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

func main() {
    // 大范围随机数
    n := rand.Int64N(1000000)
    fmt.Printf("0-999999: %d\n", n)
}

IntN

定义:

func IntN(n int) int

说明:

  • 功能:返回 [0, n) 范围内的随机 int
  • 参数n - 上界(必须 > 0)
  • 返回值int
  • 注意:n <= 0 时会 panic
  • 变化:v2 版本使用 IntN 替代了 v1 的 Intn

示例:

package main

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

func main() {
    // 模拟骰子
    dice := rand.IntN(6) + 1
    fmt.Printf("骰子点数:%d\n", dice)
    
    // 随机数组索引
    items := []string{"苹果", "香蕉", "橙子", "葡萄"}
    randomItem := items[rand.IntN(len(items))]
    fmt.Printf("随机选择:%s\n", randomItem)
}

N

定义:

func N[Int intType](n Int) Int

说明:

  • 功能:泛型版本的范围随机数生成
  • 类型参数Int - 整数类型(int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64)
  • 参数n - 上界(必须 > 0)
  • 返回值Int - [0, n) 范围内的随机数
  • 特点:Go 1.22+ 泛型支持

示例:

package main

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

func main() {
    // 使用泛型函数
    fmt.Printf("int8: %d\n", rand.N[int8](100))
    fmt.Printf("int16: %d\n", rand.N[int16](1000))
    fmt.Printf("uint32: %d\n", rand.N[uint32](10000))
    fmt.Printf("uint64: %d\n", rand.N[uint64](1000000))
}

NormFloat64

定义:

func NormFloat64() float64

说明:

  • 功能:返回标准正态分布的 float64
  • 返回值float64 - 范围 [-MaxFloat64, +MaxFloat64]
  • 分布:均值=0,标准差=1
  • 用途:模拟自然现象、蒙特卡洛模拟

示例:

package main

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

func main() {
    // 生成标准正态分布样本
    fmt.Println("标准正态分布 (μ=0, σ=1):")
    for i := 0; i < 5; i++ {
        fmt.Printf("%.4f\n", rand.NormFloat64())
    }
    
    // 调整均值和标准差
    mean := 100.0
    stddev := 15.0
    sample := rand.NormFloat64()*stddev + mean
    fmt.Printf("\n调整后 (μ=%.0f, σ=%.0f): %.4f\n", mean, stddev, sample)
}

Perm

定义:

func Perm(n int) []int

说明:

  • 功能:返回 [0, n) 的随机排列
  • 参数n - 排列长度
  • 返回值[]int - 随机排列的切片

示例:

package main

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

func main() {
    // 生成 0-9 的随机排列
    perm := rand.Perm(10)
    fmt.Printf("随机排列:%v\n", perm)
    
    // 洗牌算法
    cards := []string{"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}
    indices := rand.Perm(len(cards))
    
    fmt.Print("洗牌后:")
    for _, idx := range indices {
        fmt.Printf("%s ", cards[idx])
    }
}

Shuffle

定义:

func Shuffle(n int, swap func(i, j int))

说明:

  • 功能:随机打乱序列
  • 参数
    • n - 序列长度
    • swap - 交换函数

示例:

package main

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

func main() {
    // 打乱切片
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    
    fmt.Printf("打乱前:%v\n", numbers)
    
    rand.Shuffle(len(numbers), func(i, j int) {
        numbers[i], numbers[j] = numbers[j], numbers[i]
    })
    
    fmt.Printf("打乱后:%v\n", numbers)
}

Uint

定义:

func Uint() uint

说明:

  • 功能:返回随机无符号整数
  • 返回值uint

示例:

package main

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

func main() {
    fmt.Printf("随机 uint: %d\n", rand.Uint())
}

Uint32

定义:

func Uint32() uint32

说明:

  • 功能:返回随机 32 位无符号整数
  • 返回值uint32 - 范围 [0, 2^32-1]
  • 变化:v2 版本新增函数

示例:

package main

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

func main() {
    fmt.Printf("随机 uint32: %d\n", rand.Uint32())
    fmt.Printf("十六进制:0x%08X\n", rand.Uint32())
}

Uint32N

定义:

func Uint32N(n uint32) uint32

说明:

  • 功能:返回 [0, n) 范围内的随机 uint32
  • 参数n - 上界(必须 > 0)
  • 返回值uint32
  • 注意:n <= 0 时会 panic
  • 变化:v2 版本新增函数

示例:

package main

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

func main() {
    fmt.Printf("0-999: %d\n", rand.Uint32N(1000))
}

Uint64

定义:

func Uint64() uint64

说明:

  • 功能:返回随机 64 位无符号整数
  • 返回值uint64 - 范围 [0, 2^64-1]
  • 变化:v2 版本新增函数

示例:

package main

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

func main() {
    fmt.Printf("随机 uint64: %d\n", rand.Uint64())
    fmt.Printf("十六进制:0x%016X\n", rand.Uint64())
}

Uint64N

定义:

func Uint64N(n uint64) uint64

说明:

  • 功能:返回 [0, n) 范围内的随机 uint64
  • 参数n - 上界(必须 > 0)
  • 返回值uint64
  • 注意:n <= 0 时会 panic
  • 变化:v2 版本新增函数

示例:

package main

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

func main() {
    fmt.Printf("0-999999: %d\n", rand.Uint64N(1000000))
}

UintN

定义:

func UintN(n uint) uint

说明:

  • 功能:返回 [0, n) 范围内的随机 uint
  • 参数n - 上界(必须 > 0)
  • 返回值uint
  • 注意:n <= 0 时会 panic
  • 变化:v2 版本新增函数

示例:

package main

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

func main() {
    fmt.Printf("0-99: %d\n", rand.UintN(100))
}

二、ChaCha8 类型

ChaCha8 结构体

定义:

type ChaCha8 struct {
    // 包含未导出的字段
}

说明:

  • 功能:ChaCha8 加密算法的随机数生成器
  • 特点
    • 加密安全的随机源
    • 需要 32 字节种子
    • 支持二进制序列化

NewChaCha8

定义:

func NewChaCha8(seed [32]byte) *ChaCha8

说明:

  • 功能:创建 ChaCha8 随机源
  • 参数seed - 32 字节种子
  • 返回值*ChaCha8

示例:

package main

import (
    "crypto/rand"
    "fmt"
    "math/rand/v2"
)

func main() {
    // 生成随机种子
    var seed [32]byte
    rand.Read(seed[:])
    
    // 创建 ChaCha8 随机源
    chacha := rand.NewChaCha8(seed)
    r := rand.New(chacha)
    
    // 使用
    fmt.Printf("随机数:%d\n", r.IntN(100))
}

ChaCha8 方法

AppendBinary

定义:

func (c *ChaCha8) AppendBinary(b []byte) ([]byte, error)

说明:

  • 功能:追加二进制编码

MarshalBinary

定义:

func (c *ChaCha8) MarshalBinary() ([]byte, error)

说明:

  • 功能:二进制序列化

Read

定义:

func (c *ChaCha8) Read(p []byte) (n int, err error)

说明:

  • 功能:生成随机字节

Seed

定义:

func (c *ChaCha8) Seed(seed [32]byte)

说明:

  • 功能:重新设置种子

Uint64

定义:

func (c *ChaCha8) Uint64() uint64

说明:

  • 功能:生成随机 uint64

UnmarshalBinary

定义:

func (c *ChaCha8) UnmarshalBinary(data []byte) error

说明:

  • 功能:从二进制数据反序列化

三、PCG 类型

PCG 结构体

定义:

type PCG struct {
    // 包含未导出的字段
}

说明:

  • 功能:PCG (Permuted Congruential Generator) 随机数生成器
  • 特点
    • 高质量的伪随机数生成器
    • 需要两个 64 位种子
    • 支持二进制序列化

NewPCG

定义:

func NewPCG(seed1, seed2 uint64) *PCG

说明:

  • 功能:创建 PCG 随机源
  • 参数
    • seed1 - 第一个种子
    • seed2 - 第二个种子
  • 返回值*PCG

示例:

package main

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

func main() {
    // 创建 PCG 随机源
    pcg := rand.NewPCG(42, 123)
    r := rand.New(pcg)
    
    // 使用
    fmt.Printf("随机数:%d\n", r.IntN(100))
    fmt.Printf("随机数:%d\n", r.IntN(100))
}

PCG 方法

AppendBinary

定义:

func (p *PCG) AppendBinary(b []byte) ([]byte, error)

说明:

  • 功能:追加二进制编码

MarshalBinary

定义:

func (p *PCG) MarshalBinary() ([]byte, error)

说明:

  • 功能:二进制序列化

Seed

定义:

func (p *PCG) Seed(seed1, seed2 uint64)

说明:

  • 功能:重新设置种子

Uint64

定义:

func (p *PCG) Uint64() uint64

说明:

  • 功能:生成随机 uint64

UnmarshalBinary

定义:

func (p *PCG) UnmarshalBinary(data []byte) error

说明:

  • 功能:从二进制数据反序列化

四、Rand 类型

Rand 结构体

定义:

type Rand struct {
    // 包含未导出的字段
}

说明:

  • 功能:随机数生成器
  • 特点
    • 不是线程安全的
    • 可自定义 Source
    • 可重现随机序列

New

定义:

func New(src Source) *Rand

说明:

  • 功能:创建新的 Rand 实例
  • 参数src - 随机源
  • 返回值*Rand

示例:

package main

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

func main() {
    // 创建 PCG 随机源
    pcg := rand.NewPCG(12345, 67890)
    r := rand.New(pcg)
    
    // 使用自定义随机源
    fmt.Printf("IntN(100): %d\n", r.IntN(100))
    fmt.Printf("Float64: %f\n", r.Float64())
    fmt.Printf("Perm(5): %v\n", r.Perm(5))
}

Rand 方法

Rand 类型的方法与包级别函数基本相同,包括:

  • ExpFloat64、Float32、Float64
  • Int、Int32、Int32N、Int64、Int64N、IntN
  • NormFloat64、Perm、Shuffle
  • Uint32、Uint32N、Uint64、Uint64N、UintN

示例:

package main

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

func main() {
    r := rand.New(rand.NewPCG(42, 123))
    
    fmt.Printf("Int32: %d\n", r.Int32())
    fmt.Printf("Int64: %d\n", r.Int64())
    fmt.Printf("Uint32: %d\n", r.Uint32())
    fmt.Printf("IntN(100): %d\n", r.IntN(100))
    fmt.Printf("Float64: %f\n", r.Float64())
}

五、Source 类型

Source 接口

定义:

type Source interface {
    Uint64() uint64
}

说明:

  • 功能:随机源接口
  • 要求:实现 Uint64() 方法
  • 用途:实现自定义随机数生成器

六、Zipf 类型

Zipf 结构体

定义:

type Zipf struct {
    // 包含未导出的字段
}

说明:

  • 功能:齐夫分布随机数生成器
  • 用途:模拟符合齐夫定律的分布

NewZipf

定义:

func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf

说明:

  • 功能:创建 Zipf 分布生成器
  • 参数
    • r - Rand 实例
    • s - 指数参数(> 1)
    • v - 偏移参数(> 0)
    • imax - 最大值
  • 返回值*Zipf

示例:

package main

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

func main() {
    r := rand.New(rand.NewPCG(42, 123))
    
    // 创建 Zipf 分布
    zipf := rand.NewZipf(r, 2.0, 1.0, 100)
    
    // 生成 Zipf 分布随机数
    fmt.Println("Zipf 分布样本:")
    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", zipf.Uint64())
    }
}

Zipf 方法

Uint64

定义:

func (z *Zipf) Uint64() uint64

说明:

  • 功能:生成符合 Zipf 分布的随机数

七、典型示例

示例 1:生成随机密码

package main

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

func generatePassword(length int) string {
    const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
    
    password := make([]byte, length)
    for i := 0; i < length; i++ {
        password[i] = charset[rand.IntN(len(charset))]
    }
    
    return string(password)
}

func main() {
    fmt.Println("随机密码生成:")
    for i := 0; i < 5; i++ {
        fmt.Printf("%d: %s\n", i+1, generatePassword(12))
    }
}

示例 2:使用 PCG 生成可重现序列

package main

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

func main() {
    // 使用相同种子创建两个相同的生成器
    pcg1 := rand.NewPCG(42, 123)
    pcg2 := rand.NewPCG(42, 123)
    
    r1 := rand.New(pcg1)
    r2 := rand.New(pcg2)
    
    fmt.Println("两个生成器应产生相同序列:")
    for i := 0; i < 5; i++ {
        n1 := r1.IntN(100)
        n2 := r2.IntN(100)
        fmt.Printf("r1: %d, r2: %d, 相同:%v\n", n1, n2, n1 == n2)
    }
}

示例 3:蒙特卡洛模拟(计算π)

package main

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

func estimatePi(samples int) float64 {
    inside := 0
    
    for i := 0; i < samples; i++ {
        x := rand.Float64()
        y := rand.Float64()
        
        // 检查点是否在单位圆内
        if x*x + y*y <= 1 {
            inside++
        }
    }
    
    // π/4 ≈ inside/samples
    return 4.0 * float64(inside) / float64(samples)
}

func main() {
    fmt.Println("蒙特卡洛方法估算π:")
    
    samples := []int{1000, 10000, 100000, 1000000}
    for _, n := range samples {
        pi := estimatePi(n)
        fmt.Printf("样本数 %7d: π ≈ %.6f\n", n, pi)
    }
}

示例 4:使用泛型函数 N

package main

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

func main() {
    // 使用泛型函数生成各种类型的随机数
    fmt.Printf("int8:   %d\n", rand.N[int8](100))
    fmt.Printf("int16:  %d\n", rand.N[int16](1000))
    fmt.Printf("int32:  %d\n", rand.N[int32](10000))
    fmt.Printf("int64:  %d\n", rand.N[int64](1000000))
    fmt.Printf("uint8:  %d\n", rand.N[uint8](100))
    fmt.Printf("uint16: %d\n", rand.N[uint16](1000))
    fmt.Printf("uint32: %d\n", rand.N[uint32](10000))
    fmt.Printf("uint64: %d\n", rand.N[uint64](1000000))
}

示例 5:模拟掷骰子

package main

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

func rollDice(sides int) int {
    return rand.IntN(sides) + 1
}

func rollMultipleDice(count, sides int) []int {
    results := make([]int, count)
    for i := 0; i < count; i++ {
        results[i] = rollDice(sides)
    }
    return results
}

func main() {
    fmt.Println("掷骰子模拟:")
    
    // 掷 10 次 6 面骰
    fmt.Println("\n10 次 d6:")
    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", rollDice(6))
    }
    
    // 掷 5 次 20 面骰
    fmt.Println("\n\n5 次 d20:")
    for i := 0; i < 5; i++ {
        fmt.Printf("%d ", rollDice(20))
    }
    
    // 3 个 6 面骰
    fmt.Println("\n\n3d6 (5 次):")
    for i := 0; i < 5; i++ {
        rolls := rollMultipleDice(3, 6)
        sum := 0
        for _, r := range rolls {
            sum += r
        }
        fmt.Printf("%v = %d\n", rolls, sum)
    }
}

示例 6:并发安全的随机数生成

package main

import (
    "fmt"
    "math/rand/v2"
    "sync"
)

// 线程安全的随机数生成器
type SafeRand struct {
    mu sync.Mutex
    r  *rand.Rand
}

func NewSafeRand(seed1, seed2 uint64) *SafeRand {
    return &SafeRand{
        r: rand.New(rand.NewPCG(seed1, seed2)),
    }
}

func (sr *SafeRand) IntN(n int) int {
    sr.mu.Lock()
    defer sr.mu.Unlock()
    return sr.r.IntN(n)
}

func (sr *SafeRand) Float64() float64 {
    sr.mu.Lock()
    defer sr.mu.Unlock()
    return sr.r.Float64()
}

func main() {
    safeRand := NewSafeRand(42, 123)
    
    var wg sync.WaitGroup
    results := make([]int, 10)
    
    // 并发生成随机数
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(idx int) {
            defer wg.Done()
            results[idx] = safeRand.IntN(100)
        }(i)
    }
    
    wg.Wait()
    
    fmt.Println("并发安全的随机数:")
    fmt.Println(results)
}

示例 7:使用 ChaCha8 加密随机源

package main

import (
    "crypto/rand"
    "fmt"
    "math/rand/v2"
)

func main() {
    // 生成加密安全的种子
    var seed [32]byte
    if _, err := rand.Read(seed[:]); err != nil {
        panic(err)
    }
    
    // 创建 ChaCha8 随机源
    chacha := rand.NewChaCha8(seed)
    r := rand.New(chacha)
    
    fmt.Println("ChaCha8 随机数生成:")
    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", r.IntN(100))
    }
    fmt.Println()
}

示例 8:抽奖系统

package main

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

type Lottery struct {
    participants []string
    winners      []string
}

func NewLottery() *Lottery {
    return &Lottery{
        participants: make([]string, 0),
        winners:      make([]string, 0),
    }
}

func (l *Lottery) AddParticipant(name string) {
    l.participants = append(l.participants, name)
}

func (l *Lottery) DrawWinners(count int) []string {
    if count > len(l.participants) {
        count = len(l.participants)
    }
    
    // 复制参与者列表
    pool := make([]string, len(l.participants))
    copy(pool, l.participants)
    
    // 抽取获奖者
    winners := make([]string, 0, count)
    for i := 0; i < count; i++ {
        idx := rand.IntN(len(pool))
        winners = append(winners, pool[idx])
        // 移除已中奖者
        pool[idx] = pool[len(pool)-1]
        pool = pool[:len(pool)-1]
    }
    
    l.winners = append(l.winners, winners...)
    return winners
}

func main() {
    lottery := NewLottery()
    
    // 添加参与者
    participants := []string{"张三", "李四", "王五", "赵六", "钱七", 
                           "孙八", "周九", "吴十", "郑十一", "王十二"}
    for _, p := range participants {
        lottery.AddParticipant(p)
    }
    
    fmt.Println("抽奖系统")
    fmt.Printf("参与者:%d 人\n", len(participants))
    
    // 抽取 3 名获奖者
    fmt.Println("\n开始抽奖...")
    winners := lottery.DrawWinners(3)
    
    fmt.Println("\n获奖者名单:")
    for i, w := range winners {
        fmt.Printf("%d. %s\n", i+1, w)
    }
}

八、最佳实践

1. 使用包级别函数(简单场景)

// ✓ 好的做法:简单场景使用包级别函数
n := rand.IntN(100)
f := rand.Float64()

// 包级别函数是线程安全的

2. 使用 PCG 或 ChaCha8(需要控制种子)

// ✓ 好的做法:需要重现性时使用 PCG
pcg := rand.NewPCG(42, 123)
r := rand.New(pcg)
n1 := r.IntN(100)

// ✓ 好的做法:需要更高质量随机数使用 ChaCha8
var seed [32]byte
cryptoRand.Read(seed[:])
chacha := rand.NewChaCha8(seed)
r := rand.New(chacha)

3. 使用泛型函数 N

// ✓ 好的做法:使用泛型函数
n := rand.N[int16](1000)
u := rand.N[uint32](10000)

4. 并发场景使用锁

// ✓ 好的做法:并发时使用锁
type SafeRand struct {
    mu sync.Mutex
    r  *rand.Rand
}

5. 安全敏感场景使用 crypto/rand

// ✗ 错误:不应用于安全场景
password := rand.IntN(1000000) // 不安全!

// ✓ 好的做法:使用 crypto/rand
import "crypto/rand"

九、与其他包配合

1. 与 crypto/rand 配合

import (
    "crypto/rand"
    "math/big"
    mrand "math/rand/v2"
)

// 生成加密安全的种子
var seed [32]byte
rand.Read(seed[:])

// 使用 ChaCha8
chacha := mrand.NewChaCha8(seed)
r := mrand.New(chacha)

2. 与 slices 包配合

import (
    "math/rand/v2"
    "slices"
)

// 打乱切片
slices.Shuffle(data, func(i, j int) {
    data[i], data[j] = data[j], data[i]
})

十、快速参考

包级别函数

函数参数返回值功能
ExpFloat64float64指数分布
Float32float32[0,1) 随机 float32
Float64float64[0,1) 随机 float64
Intint随机非负 int
Int32int32随机 32 位 int
Int32Nn int32int32[0,n) 随机 int32
Int64int64随机 64 位 int
Int64Nn int64int64[0,n) 随机 int64
IntNn intint[0,n) 随机 int
Nn IntInt泛型 [0,n) 随机数
NormFloat64float64标准正态分布
Permn int[]int[0,n) 随机排列
Shufflen int, swap打乱序列
Uintuint随机 uint
Uint32uint32随机 uint32
Uint32Nn uint32uint32[0,n) 随机 uint32
Uint64uint64随机 uint64
Uint64Nn uint64uint64[0,n) 随机 uint64
UintNn uintuint[0,n) 随机 uint

随机源类型

类型构造函数特点
PCGNewPCG(seed1, seed2 uint64)高质量 PCG 生成器
ChaCha8NewChaCha8(seed [32]byte)加密安全生成器

v1 vs v2 变化

v1v2说明
Int31Int3232 位整数
Int31nInt32N命名规范化
Int63Int6464 位整数
Int63nInt64N命名规范化
IntnIntN命名规范化
-Uint32新增
-Uint32N新增
-Uint64新增
-Uint64N新增
-UintN新增
-N泛型支持

十一、注意事项

1. 不适用于安全场景

// ✗ 不安全的做法
token := rand.Int64() // 可预测!

// ✓ 安全的做法
import "crypto/rand"
n, _ := rand.Int(rand.Reader, big.NewInt(1000000))

2. 并发安全

// 包级别函数是线程安全的
// Rand 对象不是线程安全的,需要加锁

3. 范围验证

// n <= 0 会 panic
rand.IntN(0)   // panic!
rand.IntN(-1)  // panic!

// ✓ 好的做法
if n > 0 {
    rand.IntN(n)
}

4. v2 的优势

  • 更好的 API 命名(Int32、Int64 等)
  • 新增 Uint 系列函数
  • 支持泛型函数 N
  • 提供 PCG 和 ChaCha8 两种高质量随机源
  • 自动种子化

最后更新: 2026-04-05
Go 版本: Go 1.22+
包文档: https://pkg.go.dev/math/rand/v2