go 언어를 사용하면서 표준 라이브러리를 확장하고 싶을때.
By SeukWon Kang
너무 간단해서 적기도 뭐한 팁이지만
가끔씩 표준 라이브러리가 제공하는 struct( class 가 아니지요 ^^) 를 확장해서 내가 필요한 함수들을 추가 하고 싶을때가 있습니다.
goguelike 에선 표준 분포에 따른 랜덤 함수를 상당히 많이 사용하는데 표준 라이브러리는 기초적인 함수만을 제공하여 더 쓰기 편한 형태의 함수를 추가해서 사용하고 있습니다.
기본적으로는 go 언어의 embedded field를 사용하는 것이고 이것을 통해서 embedded된 struct가 제공하는 함수들이외에도 원하는 함수를 추가해 사용할수 있습니다.
//start
package rand
import (
r "math/rand"
"time"
)
type Rand struct {
*r.Rand
}
func (rnd *Rand) IntRange(s, e int) int {
return rnd.Intn(e-s) + s
}
func (rnd *Rand) NormIntRange(desiredMean, desiredStdDev int) int {
return int(rnd.NormFloat64()*float64(desiredStdDev)) + desiredMean
}
func (rnd *Rand) NormFloat64Range(desiredMean, desiredStdDev float64) float64 {
return rnd.NormFloat64()*desiredStdDev + desiredMean
}
func GetNewRand() *Rand {
return &Rand{
r.New(r.NewSource(time.Now().UnixNano())),
}
}
//end
이렇게 만들어서 “math/rand” 대신 위 패키지를 import해서 사용하면 됩니다. 기존 rand 패키지의 Rand struct 가 제공하는 모든 함수를 사용하면서 새로 추가한 함수들도 사용할수 있습니다.
주의할점은 표준 rand 패키지가 제공하는 모든 함수(특히 암묵적으로 전역 선언된 Rand object를 사용하는 ) 를 사용 할수 있는것은 아닙니다.
애초에 이 패키지를 만들게 된 이유도 이 전역 rand object를 사용하고 있었는데 언제나 처럼 profiling을 통해서 성능 개선을 하려고 해보니 이 전역 Rand object를 사용하는 부분에서 엄청난 양의 lock이 걸리고 있더군요.
그리서 모두 local Rand object를 쓰도록 바꾸면서 이왕 하는 김에 만든 코드입니다.
ps) 2015-02-03 추가 생각해보니 GetNewRand 함수는 표준 라이브러리와 같이 New 함수로 바꾸는 것이 더 좋겠네요. (함수에 get , set 을 붙이는 것이 꽤 오랜 습관이라 ) goguelike에서도 도 이름을 바꿨습니다.
ps) 2015-02-14 추가 github에 코드를 올렸습니다. https://github.com/kasworld/rand