map接口指针方法接收器

时间:2015-07-18 19:17:53

标签: dictionary go

我有以下代码

http://play.golang.org/p/d-bZxL72az

package main

import "fmt"

type Variables struct {
    sum     uint64
    highest uint64
}

type Data struct {
    count  uint64
    mValue map[string]Variables
}

func (v Variables) Add(value Variables) Variables {
    v.sum += value.sum
    if v.highest == 0 {
        v.highest = value.highest
    } else if v.highest < value.highest {
        v.highest = value.highest
    }
    return v
}

func (v *Variables) AddPointer(value Variables) {
    v.sum += value.sum
    if v.highest == 0 {
        v.highest = value.highest
    } else if v.highest < value.highest {
        v.highest = value.highest
    }
}

func main() {
    var instances [2]Variables
    instances[0] = Variables{sum: 5, highest: 3}
    instances[1] = Variables{sum: 10, highest: 2}
    var d Data
    d.mValue = make(map[string]Variables)
    for i:= 0; i < len(instances); i++ {
        d.mValue["one"] = d.mValue["one"].Add(instances[i])
        d.mValue["two"].AddPointer(instances[i])
    }
    fmt.Println(d.mValue["one"])
    fmt.Println(d.mValue["two"])
}

我收到错误

# command-line-arguments
/tmp/sandbox209565070/main.go:42: cannot call pointer method on d.mValue["two"]
/tmp/sandbox209565070/main.go:42: cannot take the address of d.mValue["two"]

(我认为)我理解第二个错误cannot take address - 因为,它是一个地图,它不能取地址(这是正确的吗?)

第一个错误的原因是否相同(不能调用指针方法)?

有没有办法在地图内的结构上使用指针方法..

2 个答案:

答案 0 :(得分:2)

是的,同样的道理。为了使用指针接收器调用方法,您需要首先使用指针,或者需要可寻址的值,Go将自动为您指针。

然后,您可以做的是mValue map[string]*Variables而不是map[string]Variables。然后,您将在地图中存储指向已经分配的,保证可寻址的Variables的指针,并且您将能够在该指针上调用方法。

答案 1 :(得分:1)

扩展上一个答案...

在实践中,这通常不是问题。如果类型在没有指针的情况下更有意义(例如,值语义更有意义的小结构)那么你就不会有指针接收器而且不会出现问题。

如果指针接收器有意义,那么您应该在大多数地方使用指向该类型的指针,例如在地图中(如hobbs said),并且您不会有使用非指针参数或返回非的方法-pointer值(非指针接收器仍然有意义并且易于使用)。同样,问题不会出现。

在第一种情况下,如果您想使用带有非指针映射条目的指针接收器,您可以使用temporary (addressable) variable并将其重新分配回地图。

    x := d.mValue["two"]
    x.AddPointer(instances[i])
    // AddPointer uses a pointer receiver; `x` needs to be addressable,
    // it will contain a copy of the value from the map and that copy may
    // be changed by the method so we need to copy the new version back
    // into the map.
    d.mValue["two"] = x

在第二种情况下,出现了一些问题。首先,要避免nil指针,您需要初始化映射条目或检查映射读取上的nil /存在(或使指针接收器方法处理nil值接收器,但是但是对于非指针接收器方法没有帮助。其次,如果由于某些愚蠢的原因你有指针但仍然有一个返回非指针的方法,你必须使用不同的语法来分配给地图。

Something like this perhaps

    // Initialize some map entries to avoid nil pointers
    d.mValue = map[string]*Variables{
        "one": &Variables{},
        "two": &Variables{},
    }
    for i := 0; i < len(instances); i++ {
        // Just calling the non-pointer reciever is easy/fine:
        d.mValue["one"].Add(instances[i])

        // But you can't do this:
        //d.mValue["one"] = d.mValue["one"].Add(instances[i])
        // cannot use d.mValue["one"].Add(instances[i]) (type Variables) as type *Variables in assignment

        *d.mValue["one"] = d.mValue["one"].Add(instances[i])
        d.mValue["two"].AddPointer(instances[i])
    }