0

Я пишу простую программу в Go как упражнение, чтобы выучить язык. Программа является игровым игроком: это текстовая игра, а затем общается с ней через StdinPipe/StdoutPipe. После некоторого обмана и чтения многих онлайн-документов мне удалось получить работу скелета - эквивалент Hello World, где я установил двустороннюю связь и могу обрабатывать ошибки, такие как завершение программы.Хранение состояния в Go

Теперь я пытаюсь написать фактический игровой код AI. Поскольку моя цель - изучать язык, я стараюсь быть очень осторожным со стилем - я не просто хочу писать C (или какой-то другой язык) в Go.

Очевидное разделение труда в программе (после завершения всей установки) состоит из двух частей. Во-первых, программа просматривает текущее состояние и решает, какую команду следует выдать игре. Во-вторых, программа просматривает возвращаемые данные и соответственно обновляет состояние. (Да, это простая игра - она ​​ждет ввода, а затем отвечает, нет проблем с синхронизацией.)

Я не уверен, куда должна идти эта информация о состоянии. Сбрасывание всего этого в глобальную сферу кажется неправильным, и создание массивного одноэлементного объекта кажется еще хуже (и Go не особенно OO). В любом случае я не хочу, чтобы функции проходили и возвращали 20+ переменных.

Общие советы в порядке, но меня больше всего интересует то, что идиоматически подходит для Go. По запросу я могу поделиться кодом, но я не думаю, что это было бы полезно.

ответ

1

Go включает style of OO programming.

Создайте тип структуры для состояния игры. Передайте указатель на значение этого типа в вашей программе или сохраните указатель в переменной уровня пакета, если это не беспокоит вас. При необходимости используйте методы этого типа. Подумайте о том, чтобы положить его в свой пакет для большей инкапсуляции.

+1

Благодарим за ответ. Если вы не возражаете, я подожду до завтра, чтобы принять ответ - я все еще размышляю над тем, какое решение лучше всего. (+1 в то же время.) – Charles

1

Мне нравится использовать пакет для этой цели.

тривиальный пример:

package foo 

func Incr() { 
    f.incr() 
} 

func Count() int { 
    return f.count() 
} 

type foo struct { 
    sync.RWMutex 
    count int 
} 

func (f *foo) incr() { 
    f.Lock() 
    f.count++ 
    f.Unlock() 
} 

func (f *foo) count() int { 
    f.RLock() 
    defer f.RUnlock() 
    return f.count 
} 

var f = &foo{} 

Этот пакет может быть импортирован в любой другой пакет и поддерживать состояние. Я добавил sync.RWMutex для предотвращения любых условий гонки. Это дает вам полный контроль над доступом к состоянию foo и прекрасно сложен.

+0

Спасибо. Позвольте мне убедиться, что я понимаю ваше предложение: я создаю 'struct', который содержит все мои переменные состояния, а затем создайте его как глобальный объект, чтобы я мог проверять и изменять состояние в моих функциях обновления. Верный? (И, конечно, я сделал +1.) – Charles

+0

@Charles Correct. Вы можете сохранить любое состояние, которое захотите, в структуре и добавить методы к этой структуре, если хотите. Позитивным для этого подхода является то, что вы можете полностью контролировать доступ и легко импортировать состояние в другие пакеты. Go net/http использует аналогичный подход с методами HandlerFunc и Handler, позволяя вам добавлять обработчики http в несколько пакетов. – jmaloney

+0

@tommywild вы можете уточнить? Довольно легко добавить foo_test и проверить что-либо в пакете. Вы также можете легко протестировать вышеуказанные функции, используя экспортированные методы. – jmaloney