go 언어에서 function object 사용하기. 반복루프 위임 패턴? (delegate loop)
By SeukWon Kang
이것 역시 대단한 팁이라긴 뭐합니다만 “작업하다 보니 이런 형태의 코드를 많이 짜고 있더라” 입니다. 주로 나오는 형태는 array/slice 들의 내용에서 조건에 맞는 뭔가를 찾아야 하는 경우에 쓰게 되더군요.
그중에 제일 짧은 코드를 예로 보면
//start
var Dir2Info = []struct {
Name string
Vt [2]int
Len float64
}{
Dir_stop: {".", [2]int{0, 0}, 0.0},
Dir_n: {"N", [2]int{0, -1}, 1.0},
Dir_ne: {"NE", [2]int{1, -1}, 1.4},
Dir_e: {"E", [2]int{1, 0}, 1.0},
Dir_se: {"SE", [2]int{1, 1}, 1.4},
Dir_s: {"S", [2]int{0, 1}, 1.0},
Dir_sw: {"SW", [2]int{-1, 1}, 1.4},
Dir_w: {"W", [2]int{-1, 0}, 1.0},
Dir_nw: {"NW", [2]int{-1, -1}, 1.4},
}
type DoFn func(int, int) bool
func Call8WayTile(ox, oy int, fn DoFn) []uint8 {
TileDirs := []uint8{}
for i := uint8(1); i <= 8; i++ {
x, y := ox+Dir2Info[i].Vt[0], oy+Dir2Info[i].Vt[1]
if fn(x, y) {
TileDirs = append(TileDirs, i)
}
}
return TileDirs
}
func main() {
// use short
action.Call8WayTile(ftp.Pos[0], ftp.Pos[1], func(x, y int) bool {
if ftp.FF.CorridorPlaceable(x, y) {
rtn = append(rtn, ftp.FF.NewCRPather(x, y))
}
return false
})
// use long
fn := func(x, y int) bool {
if aib.f.Field.CharOverwrap(x, y) {
return false
}
return aib.floorAOs.IterAtXY(x, y, func(o idpos.IDPosI) bool {
ao := o.(*activeobj.ActiveObj)
if ao.HP > 0 {
return true
}
return false
})
}
dirs := action.Call8WayTile(aib.aopos[0], aib.aopos[1], fn)
if len(dirs) == 0 {
return action.ActInvalid
}
}
//end
주어진 좌표 주변 8개 위치에 대해 fn을 실행하고 성공한 방향을 돌려주는 함수 입니다. AI등에서 아주 많이 쓰이게 되는 함수지요.
실제 goguelike 코드의 일부를 복사해 온것이라 그대로는 실행되지 않습니다. 형태만을 참고하시면 됩니다. 짧은 형태는 그냥 주변 8방향 타일에 대해 함수를 실행한 경우고 긴 형태는 실행해서 성공한 방향이 있는지를 추가로 확인 하는 경우입니다.
go 언어에서 이 anonymous function ( function object ) 은 closure 와 함께쓰일때 더 큰 위력을 발휘하게 됩니다.
이런 류의 코드가 항상 그러하듯이 너무 많이 쓰면 가독성과 유지보수성이 떨어지므로 적절하게 사용하는 것이 필요하지요.
ps) 2015-02-14 추가 예로 사용된 코드는 github의 https://github.com/kasworld/findnear 에 있습니다.