2012-10-27 6 views
6

構造体であるCompany型があり、Person型のマップも含まれています。これらの構造体もすべて構造体です。マップ内の構造体にポインタメソッドを呼び出す

type Company struct { 
    employees map[int]Person 
} 

type Person struct { 
    [...] 
} 

従業員マップにいくつかのPersonを割り当てた後、私はこれらのそれぞれに対してポインタメソッドを呼び出そうとしています。ゴーコンパイラでこの無残に失敗した

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

、私はcompany.employees上のポインタのメソッドを呼び出すことができないことを訴えて[i]を、だけでなく、私はcompany.employeesのアドレスを取ることができないよう[i]。しかし 、非ポインタ方法に初期化メソッドを設定し、それが人のコピーを返すせ、それではありません

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

作品を、使用して再びマップにそれを割り当て異なる。

これまで指針で作業していなかったので、これは私にとってかなりバグです。マップは不変ではなく、どちらの方法でも変更されるため、マップ内のエンティティでポインタメソッドを呼び出すことは問題ではありません。

誰でも私がここで間違っていることを説明することができますか、私の考えを修正してください。私は喜んでいます。例えば

答えて

11

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

オペランドは、変数、ポインタ間接またはスライスのインデックス作成操作のいずれかをアドレス可能にする必要があります。またはアドレス指定可能なstructオペランドのフィールドセレクタ。またはアドレス指定可能な配列の配列インデクシング操作である。アドレス可能性要件の例外として、xは複合リテラルであってもよい。

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

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

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

+1

これを明確にしていただきありがとうございます。私は両方のヒントを守り、Initializeメソッドを削除しましたが(とにかくそれはちょっとした名前でしたが)、そのビットを含むNewPerson()関数を作成し、初期化された人物を返しました。 Person-pointerを扱ったマップを使用することで、NewPerson()とあまり関係がなくなり、より理解しやすいコードになりました。 –

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} 
関連する問題