8

すべての構造体である Person のマップを含む、構造体である Company 型があります。

type Company struct {
    employees map[int]Person
}

type Person struct {
    [...]
}

一部の Person を employees-map に割り当てた後、これらのそれぞれでポインタ メソッドを呼び出そうとしています。

func (company *Company) Populate(names []string) {
    for i := 1; i <= 15; i++ {
        company.employees[i] = Person{names[i - 1], [...]}
        company.employees[i].Initialize()
    }
}

これは惨めに失敗し、go-Compiler はcompany.employees[i]でポインター メソッドを呼び出せず、company.employees[i]のアドレスを取得できないと不平を言っています。ただし、Initialize メソッドを非ポインター メソッドに設定し、 person のコピーを返してもらい、それを使用して再度マップに割り当てます。

company.employees[i] = company.employees[i].Initialize()

動作しますが、それほど違いはありません。

ポインタを扱ったことがないので、これは私を非常に悩ませます。マップは不変ではなく、どちらの方法でも変更されるため、マップ内のエンティティでポインター メソッドを呼び出すことは問題にならないはずです-少なくとも私の頭の中では。

ここで私が間違っていることを誰かが説明してくれたり、私の考えを正してくれたりしたら、私は喜んでいます。

4

2 に答える 2

15

ここでの問題は、ポインター メソッドを呼び出すために、 のアドレスをemployees[i]取得する必要があることです。Go仕様によると:

オペランドはアドレス可能でなければなりません。つまり、変数、ポインター間接化、またはスライス インデックス操作のいずれかです。または、アドレス指定可能な構造体オペランドのフィールド セレクター。または、アドレス指定可能な配列の配列インデックス操作。アドレス可能性要件の例外として、x は複合リテラルの場合もあります。

マップのインデックス作成操作はアドレス指定できません。これは、マップの実装が値のアドレスが変更されないことを保証する必要がないように決定されました。マップに追加されるデータが増えると、効率上の理由からデータが再配置される場合があります。

それで、どうすればそれを修正できますか?がある場合map[int]*Person、マップ値はすでにアドレスであるため、マップ内のデータのアドレスを取得する必要はありません。

最後のアドバイスPerson.Initialize()は、あまり慣用的な Go コードではありません。型を初期化する必要がある場合、通常はNewPerson()関数を使用します。このNewPerson()関数は、初期化された Person 構造体またはポインターを返します。

于 2012-10-27T15:41:21.303 に答える
0

例えば、

package main

import "fmt"

type Person struct {
    Name string
}

func NewPerson(name string) *Person {
    return &Person{Name: name}
}

type Company struct {
    Employees map[int]*Person
}

func (c *Company) Populate(names []string) {
    c.Employees = make(map[int]*Person)
    for i := range names {
        c.Employees[i+1] = NewPerson(names[i])
    }
}

func main() {
    c := Company{}
    c.Populate([]string{"Peter", "Paul"})
    for k, v := range c.Employees {
        fmt.Println(k, *v)
    }
}

出力:

1 {Peter}
2 {Paul}
于 2012-10-27T15:21:40.737 に答える