首页 > 解决方案 > Pointer values rewritten in struct when appending to slice struct

问题描述

I've been dealing with a weird issue today.

So, I've been trying to get values from a map and assign to a slice of struct type variable. But somehow the pointer value in a struct key gets rewritten, not sure why. I've written a sample code to demonstrate the problem.

package main

import "fmt"

type PType []struct {
    Main  string
    PVals *[]string
}

var mkey = map[string][]string{
    "xpos": {"123", "234", "543"},
    "ypos": {"-12", "9", "0"},
}

func main() {
    var db PType
    for mval, pval := range mkey {
        db = append(db, struct {
            Main  string
            PVals *[]string
        }{
            Main:  mval,
            PVals: &pval,
        })
    }
    for _, x := range db {
        fmt.Printf("Main: %+v | PVal: %+v\n", x.Main, x.PVals)
    }
}

The value of the key PVals in the struct db gets overwritten somehow in memory resulting in the output:

Main: xpos | PVal: &[-12 9 0]
Main: ypos | PVal: &[-12 9 0]

...which should ideally be

Main: xpos | PVal: &[123 234 543]
Main: ypos | PVal: &[-12 9 0]

The problem is fixed if I change the type of the PType.PVals from *[]string to just []string.

What am I doing wrong keeping pointers?

Here a playground link if that helps: https://play.golang.org/p/IVOUfTvoLt6

标签: gostruct

解决方案


In a for loop, the addresses of the loop variables are fixed. Every iteration rewrites the loop variables. When you add the address of the loop variable in the maps, you add the same slice that gets overwritten at each iteration. So you end up with a map whose values are pointing to the same location.

Without the pointer, a copy of the loop variable is placed in the map.


推荐阅读