首页 > 解决方案 > 使用 rand.Seed() 填充结构映射仅插入最后一个对象

问题描述

我有下面的代码,它的目的只是创建一个ComicBook结构对象的映射并调用一个复制映射然后打印它的函数。当我在一切正常的情况下删除该rand.Seed()行时SetId()(除了 id 对每次运行都是恒定的,正如预期的那样),否则它只会将最后一个元素添加到地图中。为什么会这样?

comicBook.go

package src

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

type ComicBook struct {
    id        int
    name      string
    publisher string
    sold      bool
}

type Book interface {
    GetId() int
    SetId() int
    GetName() string
    GetPublisher() string
    GetIsSold() bool
    New(name string, author string) ComicBook
}

func (book ComicBook) SetId()  int{
        rand.Seed(time.Now().UTC().UnixNano())
        id := rand.Intn(100)
        book.id = id
    return id
}

func (book ComicBook) New(name string, author string) ComicBook {
    id := book.SetId()
    b := ComicBook{id, name, author, false}
    return b
}

func (book ComicBook) GetId() int{
    return book.id
}

func (book ComicBook) GetName() string{
    return book.name
}

func (book ComicBook) GetPublisher() string{
    return book.publisher
}

func (book ComicBook) GetIsSold() bool{
    return book.sold
}

main.go

package main

import (
    "awesomeProject1/src"
    "fmt"
)

var (
    ComicBook src.ComicBook
)

func copyMap(m map[int]src.ComicBook) map[int]src.ComicBook {
    newMap := make(map[int]src.ComicBook)
    for k, v := range m {
        newMap[k] = v
    }
    return newMap
}

func main()  {
    b := src.ComicBook{}.New("A", "B")
    bTwo := src.ComicBook{}.New("The Dark Knight Returns", "DC Comics")
    bThree := src.ComicBook{}.New("Watchmen", "DC Comics")
    m := map[int]src.ComicBook{
        b.GetId():    b,
        bTwo.GetId(): bTwo,
        bThree.GetId(): bThree,
    }
    newMap := copyMap(m)
    for k, v := range newMap {
        fmt.Println("Id: ", k, ", Name: ", v.GetName(), ", Publisher: ", v.GetPublisher(), ", Sold: ", v.GetIsSold())
    }
}

输出:

Id: 91 , Name: Watchmen , Publisher: DC Comics , Sold: false

标签: go

解决方案


您使用不安全的方法生成 id。我测试你的代码:

https://play.golang.org/p/S0_CWMqNH2-

rand.Seed(time.Now().UTC().UnixNano())
fmt.Println(time.Now().UTC().UnixNano())
id := rand.Intn(100)
fmt.Println(id)

这个不保存。您可以认为,相同的键可以是 1/100 BUT。您没有读到这些操作之间的时间可能太短,因此密钥本身与我的测试相同:

1257894000000000000
0
1257894000000000000
0
1257894000000000000
0

使用单个变量来保存种子,如下所示:(我使用全局变量,但您可以在 ComicBook 结构中添加种子变量)

import (
    "math/rand"
    "fmt"
)
var seed int

...

func (book *ComicBook) SetId()  int{
    seed += 1
    rand.Seed(int64(seed))
    id := rand.Intn(100)

并测试:

1
81
2
86
3
8

在您的代码中,任何地图元素都有 0 键并相互重写,但现在:

map[8:{8   false} 81:{81   false} 86:{86   false}]
map[8:{8   false} 81:{81   false} 86:{86   false}]
Id:  86 , Name:   , Publisher:   , Sold:  false
Id:  8 , Name:   , Publisher:   , Sold:  false
Id:  81 , Name:   , Publisher:   , Sold:  false

https://play.golang.org/p/Z9_tFNdlBqp

并且,如果对 id 使用变量,则无需使用 rand:

func (book *ComicBook) SetId()  int{
    seed += 1
    book.id = seed
    fmt.Println(book.id)
    return seed
}

推荐阅读