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条)

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)