|
|
|
|
|
by learc83
4125 days ago
|
|
I built ported part of a distributed system I have in production to Go about 2 years ago. I remember doing a lot of reflection trying to factor out some common SQL code. Like this: func CreateRecord(record interface{}) (err error) {
t := reflect.TypeOf(record)
v := reflect.ValueOf(record)
Where I named the struct the same thing as the table it mapped to. |
|
I've used this pattern myself in a generic "game server" that implements a network protocol and manages creating "rounds" of games and other high-level bookkeeping, where you pass it in a "prototypical" game object that provides a "CreateNew()" method on it, thus making it so the core engine can create new games without ever actually knowing what the game itself is.
If it's good enough for Haskell it's good enough for Go.
(Haskell, a bit confusingly, calls this a Proxy, perhaps because the instance is standing in as a proxy for the type? I was never quite sure where the name came from.)
I've actually written quite a bit of Go now without needing reflection, and the only "interface{}"s in the system are either A: things that legitimately can be "anything" (on a per-instance basis, i.e., not ATDs that really want to just have one type in them but legitimately on an object-by-object basis may contain an "anything") or B: things I really want to say are "encodable/decodable as JSON by the standard encoding/json library but there's no clear way to say that in the type". The latter annoys me in theory a great deal more than it annoys me in practice.
Mind you, I acknowledge there's a point where you'll be left with no other options but an interface{} or reflection, but people do end up reaching for it more quickly than is strictly speaking necessary. And it isn't necessarily a compliment for Go that it makes you think a bit harder for this sort of thing.