При value receiver метод получает копию структуры: изменения полей внутри метода не видны вызывающему коду. При pointer receiver метод работает с оригиналом - изменения сохраняются. Кроме того, value receiver при каждом вызове копирует структуру (дорого для больших структур).
type Counter struct { n int }
func (c Counter) Inc() { c.n++ } // копия, вызывающий не видит изменения
func (c *Counter) IncP() { c.n++ } // оригинал
var x Counter
x.Inc()
fmt.Println(x.n) // 0
x.IncP()
fmt.Println(x.n) // 1
Правило: если хотя бы один метод должен быть с pointer receiver (например, потому что меняет состояние), делайте pointer receiver для всех методов типа, чтобы не смешивать семантику.