“make”函数对此上下文中的地图有何作用

时间:2016-01-23 04:04:33

标签: struct go

我是Go的新手,几天前正在寻找关于表单的教程,现在我已经熟悉了一点,我试图创建自己的错误处理程序,我可以使用我的所有结构,有点像抽象类,但我从我看到的教程中得到的例子让我有点难过。

这是我用来测试make函数正在做什么的一个小例子。我有点想通过修补来解决这个问题,但我不明白实际做什么,以及为什么有必要。

type ErrorHandler struct {
    Errors map[string]string
}

type Form struct {
    ErrorHandler
}

func main() {
    form := &Form{}

    if true {
        fmt.Printf("%p\n", &form.Errors)
    } else {
        form.Errors = make(map[string]string)
        fmt.Printf("%p\n", &form.Errors)
    }
}

在上面的示例中,我尝试将if语句从true更改为false,以查看内存地址是否根据是否使用make函数而更改,并且两种情况都保持不变。我读了答案here,他说它的一个用途是“创建一个预先分配空间的地图” - 这对我来说并不重要,因为我是新手指针而且所有这些,但是“创建一个地图”部分让我觉得这就像在ErrorHandler结构中重新初始化Errors映射一样,它会将它分配给一个新的内存地址,是吗?但不,他们保持不变。

所以我尝试在地图中创建一个值,一旦没有 make函数,一次 with make函数。 if条件给出了一个错误assignment to entry in nil mapgoroutine [running]else语句打印出“haha”,这就是我设置的内容:

type ErrorHandler struct {
    Errors map[string]string
}

type Form struct {
    ErrorHandler
}

func main() {
    form := &Form{}

    if true {
        form.Errors["blah"] = "haha"
        fmt.Printf(form.Errors["blah"])
    } else {
        form.Errors = make(map[string]string)
        form.Errors["blah"] = "haha"
        fmt.Printf(form.Errors["blah"])
    }
}

所以我看看make函数在做什么,但不完全正确。据我所知,如果我要将项目“推”到该地图中,我需要使用make函数,但我不明白为什么它是必要的。为什么map[string]string在我的结构中设置为nil,因为当我将其打印出来时,我看到“map []”而不是“nil”...这令人困惑。

有人可以解释一下吗?这个goroutine怎么用?也许这就是我正在寻找的答案..之前从未使用过。

此外,由于我必须使用make,是否有办法让它自动发生而不必将其放在每个方法的顶部?

例如,在我的ErrorHandler结构中,我有一个如下所示的方法:

func (this *ErrorHandler) HandleErr(err string) {
    this.Errors = make(map[string]string)
    this.Errors["Error"] = err
}

并在我的Form结构中我还有另一个方法来验证表单,但也使用方法顶部的`this.Errors = make(map [string] string)...感觉非干我

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

将地图视为包含指向底层地图结构和大小的指针的结构(可能还有其他东西,不确定)。

例如,将其视为:

struct Map {
  data *Entries
  size int
}

make,根据传递给make的大小(如果有的话)分配条目的初始值

当你说:

form.Errors = make(map[string]string)

它说:

form.Errors = struct { data : malloc(sizeof(Entries)*capacity), size : 0 }

复制"数据"和"尺寸"表单中的变量。错误

实际字段" form.Errors"在内存中仍然是相同的位置,form的内部值。错误已经改变以匹配返回的内容。

因此,当您查看& form.Errors

时,地址不会改变

至于推送到地图时的nil错误,你没有make ......

非女仆地图没有"数据"段,所以你得到一个零指针错误。

与做:

不同
var i *int
*i = 5

也导致零错误

希望所有这些都有意义,并有助于解决混乱问题。

答案 1 :(得分:1)

首先,回答你的问题:

来自https://golang.org/pkg/builtin/#make

  

make内置函数分配并初始化slice,map或chan类型的对象(仅限)[...]

     

地图:初始分配是根据大小而不是   结果映射的长度为0.在这种情况下,可以省略大小   分配一个小的起始大小。

其次,您发布的代码中没有goroutines。

第三,让初始化地图,你可能不应该在每个HandleErr调用中使用它,因为它会替换你当前的地图。我认为您想要的可能是NewErrorHandlerNewForm等初始化函数。这是你的结构的一种制作方式。例如:

func NewErrorHandler() ErrorHandler {
    return ErrorHandler{make(map[string]string)}
}

最后为什么无法自动初始化地图?如果确实如此,您将无法控制地图的初始大小。如果您拥有关键任务代码并且希望它是快速或低内存并且知道大小,则可能很重要。

PS。还有另一种初始化地图的方法。如果要初始化空地图,可以写:map[string]string{}。如果要创建具有初始值的地图:

map[string]string{
    "a": "b",
    "c": "d",
}

所以你可以写NewErrorHandler函数,如:

func NewErrorHandler() ErrorHandler {
    return ErrorHandler{map[string]string{}}
}