dregvw1801 2018-10-01 22:44
浏览 76
已采纳

如何分配内存以映射指向golang中的切片

Is there a way to allocate the memory of a map, which has at most Nmax keys, that points to a slice of maximum length Nmax?

I'm currently just specifying the max number of keys via make(map[int][]int,Nmax), but I'm not sure how to tell Go that each slice will be of maximum length Nmax because I don't know what the keys will be apriori.

I essentially have a bunch of sites with an integer population. I use the map to keep track of how many sites have a given population N. The bottleneck in my program appears to be runtime.memmove, which I'm guessing comes from constant resizing of the slice the map points to.

  • 写回答

2条回答 默认 最新

  • douya1974 2018-10-02 13:31
    关注

    So given that your description of the problem is really rather vague, I'll just start by saying how I'd go about "managing" the map. To keep things simple, I'm going to wrap all the logic up in receiver functions, so wrapping the map up in a custom type:

    type dataMap struct {
        data map[int][]int
        nmax int
    }
    
    func New(Nmax int) *dataMap {
        return &dataMap{
            data: make(map[int][]int, Nmax),
            nmax: Nmax,
        }
    }
    
    // Get - return slice for given key
    func (d dataMap) Get(k int) []int {
        s, ok := d.data[k]
        if !ok {
            return nil // optionally return error
        }
        return s
    }
    
    // Set - set/append values to a given key - this is not safe for concurrent use
    // if that's needed, add a RWMutex to the type
    func (d *dataMap) Set(k int, vals ...int) error {
        s, ok := d.data[k]
        if !ok {
            s = make([]int, 0, d.nmax) // allocate slice of given length
        }
        // optionally check for nil-values + ensure we're not exceeding the nmax
        checked := make([]int, 0, len(vals))
        for i := range vals {
            if vals[i] != 0 {
                checked = append(checked, vals[i])
            }
        }
        if len(s) + len(checked) > d.nmax {
            return errors.New("max capacity exceeded")
        }
        s = append(s, checked...) // append values
        d.data[k] = s // update map
        return nil
    }
    

    This cuts down on needless memory (re-)allocation calls. It also ensures that I can get the length of any slice in the map in an O(1) operation, without having to worry about nil values:

    myData := New(10)
    fmt.Println(myData.Set(4, 1, 2, 3, 4))
    fmt.Println(len(myData.Get(4))) // 4
    fmt.Println(cap(myData.Get(4))) // 10
    // nil-values are filtered out
    myData.Set(4, 5, 6, 7, 0, 0, 0, 0)
    fmt.Println(len(myData.Get(4))) // 7
    fmt.Println(cap(myData.Get(4))) // 10
    // exceeding capacity of 10
    fmt.Println(myData.Set(4, 8, 9, 10, 11)) // max capacity exceeded
    

    working demo


    You could manage the capacity by using an array instead of a slice, but that does require you to manually keep track of the index/offset at which you want to start appending values. Generally speaking, you don't use arrays in golang lest in very, very specific cases. In this case, I'd just opt for a slice with a set cap. The advantage of this is that you could, for example have slices of different lengths. The result is very easy to test, too, because a type like this lends itself quite well to replacing it with an interface type

    type DataContainer interface {
        Get(k int) []int
        Set(k int, vals ...int) error
        Declare(k, capacity int) error // error if k is already in use?
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 酬劳2w元求合作写文章
  • ¥15 在现有系统基础上增加功能
  • ¥15 远程桌面文档内容复制粘贴,格式会变化
  • ¥15 关于#java#的问题:找一份能快速看完mooc视频的代码
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”
  • ¥15 网络设备配置与管理这个该怎么弄
  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图