2010-12-21 2 views
50

내가 Golang에 새로운 오전 구조체 nil pointer panic.초기화하는 방법을 회원

내가 다른 기능을 사용하고 호출하여 주위에 작업 한

바로 new() 후 :

func (m *SyncMap) Init() { 
     m.hm = make(map[string]string) 
     m.lock = new(sync.RWMutex) 
} 

하지만 가능하다면 내가 궁금이 상용구 초기화 없애?

답변

63

당신은 단지 생성자가 필요합니다. 일반적인 사용 패턴은 더 구조체 내부 필드, 백엔드로 goroutine을 시작하거나,이 생성자에서 수행 할 수있는 종료 자 모두를 등록하는 경우

func NewSyncMap() *SyncMap { 
    return &SyncMap{hm: make(map[string]string)} 
} 

입니다.

func NewSyncMap() *SyncMap { 
    sm := SyncMap{ 
     hm: make(map[string]string), 
     foo: "Bar", 
    } 

    runtime.SetFinalizer(sm, (*SyncMap).stop) 

    go sm.backend() 

    return &sm 
} 
+1

감사합니다. 이제 튜토리얼에서 생성자에 관한 것이 있었지만 Java 개발자라면 새로운 연산자가 아닌 New 연산자와 관련이 있어야한다고 생각했습니다. 코드 규칙 –

+1

이 방법이 효과적 일 수 있지만 최선의 조언은 아닙니다. RWMutex는 포인터가 아닌 값으로 포함되어야합니다. 0 값은 바로 사용할 수있는 뮤텍스이므로이 방법을 사용하면 명시 적 생성자 함수를 피할 수 있습니다. – kelnos

+0

예를 들어 다른 이름을 사용 했어야합니다. 보시다시피 원래 구조체의 일부가 아닌 'foo'필드를 초기화합니다. ;) – Mue

9

뮤텍스가 초기화되지 않았기 때문에 '뮤'솔루션이 작동하지 않습니다. 다음의 수정 작업 :

package main 

import "sync" 

type SyncMap struct { 
     lock *sync.RWMutex 
     hm map[string]string 
} 

func NewSyncMap() *SyncMap { 
     return &SyncMap{lock: new(sync.RWMutex), hm: make(map[string]string)} 
} 

func (m *SyncMap) Put (k, v string) { 
     m.lock.Lock() 
     defer m.lock.Unlock() 
     m.hm[k] = v 
} 

func main() { 
    sm := NewSyncMap() 
    sm.Put("Test", "Test") 
} 

http://play.golang.org/p/n-jQKWtEy5

+0

왜'sync.RWMutex'에 대한 포인터를 사용합니까? – Danilo

+0

정말 고마워요! 초기화되지 않은 뮤텍스는 디버그하기가 매우 어려운 미묘한 오류를 발생시킵니다. Lock() 및 Unlock()에 대한 호출은 성공하지만 액세스는 동기화되지 않습니다. – Steve

5

좋은 캐치 데몬에 의해. Mue는 잠금 장치를 포인터가 아닌 값으로 포함하는 일반적인 패턴을 생각할 수도있었습니다. 뮤텍스의 0 값은 즉시 사용할 수있는 잠금 해제 뮤텍스이므로 초기화가 필요하지 않으며 값을 포함하는 값을 포함하는 것이 일반적입니다. 더 단순하게하기 위해 필드 이름을 생략하여 포함시킬 수 있습니다. 그런 다음 구조체는 뮤텍스 세트를 가져옵니다. 이 작업 예제, http://play.golang.org/p/faO9six-Qx을 참조하십시오. 또한 나는 연기의 사용을 꺼냈다. 어느 정도 그것은 선호도와 코딩 스타일의 문제이지만, 오버 헤드가 적기 때문에 작은 함수에서, 특히 조건부 코드가없는 경우에는 사용하지 않는 경향이 있습니다.