sorry for the title , i don't know how to say that
i have a questions about this code
func ip2long(ip string) (ret int64) {
p:= strings.Split(ip, ".")
n, _:= strconv.Atoi(p[0])
ret += int64(n)*16777216
n, _= strconv.Atoi(p[1])
ret += int64(n)*65536
n, _= strconv.Atoi(p[2])
ret += int64(n)*256
n, _= strconv.Atoi(p[3])
ret += int64(n)
return
}
I want to convert an ip address to integer number
you see I have wrote such ugly code
first retrive number from strconv.Atoi then convert it to int64
How to simplify this ?
If you want to parse multiple integers from a string, try the Sscanf function, like this:
func main() {
var ip [4] uint32
addr := "192.168.0.1"
_, err := fmt.Sscanf(addr, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ip)
fmt.Println(ip[0]<<24 + ip[1]<<16 + ip[2]<<8 + ip[3])
}
This construct is heavy but appears more natural if you, as you probably should, were catching the parsing errors.
This being said, the correct solution to that exact problem is to use the existing net.ParseIP function which builds an IP
func ParseIP(s string) IP
If you must keep your current function prototype, I suggest this :
func ip2long(s string) (ret int64) {
bip := ([]byte)(net.ParseIP(s).To4())
return (int64)(bip[0]) * (1 << 24) + (int64)(bip[1]) * (1 << 16) + (int64)(bip[2]) * (1 << 8) + (int64)(bip[3])
}
Note that you may add a test on the return of ParseIP (which is nil in case of error)
I don't recommend it, because you would be ignoring errors, but you can write a function to give you the first value:
func first(x int, _ error) int {return x;}
Then use first(strconv.Atoi(p[0])) in your code.
For the particular code you listed though, I would use the (well tested!) standard library's net.ParseIP() and net.To4() functions:
// WARNING untested code!!
type InvalidIP string
func (InvalidIP ipStr) Error() string {
return "Invalid IPv4 address: "+ipStr
}
func ip2long(ipStr string) (ret int64, err error) {
var ip net.IP
if ip = net.ParseIP(ipStr); ip == nil {
return 0, InvalidIP(ip)
}
if ip = ip.To4(); ip == nil {
return 0, InvalidIP(ip)
}
for b := range ip {
ret <<= 8
ret += b
}
return ret, nil
}
Note that the above code adds error checking, and also accepts IPv6 formatted v4 addresses "::FFFF:C0A8:0101". Consider whether you really need an int64 type to represent IP addresses, or whether the standard library's net.IP type is good enough for your purposes.
Related
I'm a beginner at go (and not a good programmer) but I wanted to write a small program which would dump from a switch the list of mac addresses & interfaces name using snmp. I store the snmp values into an array of struct using multiple loops (the code here is to show the behavior).
During the first loop, I store Ports Vlan id & mac addresses into an array of struct (var allTableArray [30]allTable). At the end of this loop, I print the content of the array to be sure the mac addresses are in the array.
But when the second loop begins (to register bridge port number), the array seems empty (fmt.Printf("deux %x\n",allTableArray[i].macAddr) and fmt.Printf("trois %s\n",allTableArray[i].ptVlan1id)).
I don't understand why my array seems empty. Do you have any idea ?
package main
import (
"flag"
"fmt"
"os"
"time"
"strings"
"github.com/soniah/gosnmp"
"math/big"
)
type oidMacAddr struct {
oid string
macaddr string
}
type allTable struct {
ptVlan1id string
macAddr []byte
brPortNb *big.Int
ifIndex *big.Int
ifName string
}
var macAddrTable [30]oidMacAddr
func main() {
flag.Parse()
if len(flag.Args()) < 1 {
flag.Usage()
os.Exit(1)
}
target := flag.Args()[0]
showMacAddrTable(target)
}
func printValue(pdu gosnmp.SnmpPDU) error {
fmt.Printf("%s = ", pdu.Name)
//fmt.Println(reflect.TypeOf(pdu.Value.([]byte)))
switch pdu.Type {
case gosnmp.OctetString:
b := pdu.Value.([]byte)
fmt.Printf("STRING: %x\n", b)
default:
fmt.Printf("TYPE %d: %d\n", pdu.Type, gosnmp.ToBigInt(pdu.Value))
}
return nil
}
func showMacAddrTable(target string) () {
var allTableArray [30]allTable
ptVlan1Oid := ".1.3.6.1.2.1.17.4.3.1.1"
brPortOid := ".1.3.6.1.2.1.17.4.3.1.2"
brPortIfIndex := ".1.3.6.1.2.1.17.1.4.1.2"
ifIndexIfName := ".1.3.6.1.2.1.31.1.1.1.1"
community := "public"
gosnmp.Default.Target = target
gosnmp.Default.Community = community
gosnmp.Default.Timeout = time.Duration(10 * time.Second) // Timeout better suited to walking
err := gosnmp.Default.Connect()
if err != nil {
fmt.Printf("Connect err: %v\n", err)
os.Exit(1)
}
var essai []gosnmp.SnmpPDU
essai, err = gosnmp.Default.BulkWalkAll(ptVlan1Oid)
if err != nil {
fmt.Printf("Walk Error: %v\n", err)
os.Exit(1)
}
for i :=0 ; i < len(essai); i++ {
s := strings.TrimPrefix(essai[i].Name, ".1.3.6.1.2.1.17.4.3.1.1")
fmt.Printf("%s = ", s)
fmt.Printf("%x\n", essai[i].Value.([]byte))
bytes := essai[i].Value.([]byte)
macAddrTable[i] = oidMacAddr {s, string(bytes)}
allTableArray[i] = allTable {ptVlan1id: s, macAddr: bytes}
if(allTableArray[i].macAddr != nil){
fmt.Printf("%x\n",allTableArray[i].macAddr)
}
}
essai, err = gosnmp.Default.BulkWalkAll(brPortOid)
if err != nil {
fmt.Printf("Walk Error: %v\n", err)
os.Exit(1)
}
for i:=0 ; i < len(essai); i++ {
s := strings.TrimPrefix(essai[i].Name, ".1.3.6.1.2.1.17.4.3.1.2")
fmt.Printf("%s = ", s)
fmt.Printf("%d\n", essai[i].Value)
for j:=0 ; j < len(allTableArray); j++ {
if (s == allTableArray[j].ptVlan1id) {
allTableArray[j] = allTable {brPortNb: gosnmp.ToBigInt(essai[i].Value) }
}
}
fmt.Printf("deux %x\n",allTableArray[i].macAddr)
fmt.Printf("trois %s\n",allTableArray[i].ptVlan1id)
}
os.Exit(1)
}
Apparently this line
allTableArray[j] = allTable {brPortNb: gosnmp.ToBigInt(essai[i].Value) }
Update each member with a new allTable instance, where every field other than brPortNb is not defined thus becomes nil.
If what you were trying to do is to update each member's brPortNb field, you could have done so by accessing the field and assign the value to it instead of assigning a new allTable to every member.
allTableArray[j].brPortNb = gosnmp.ToBigInt(essai[i].Value)
Also, try simplifying your loops like this, provided len(essai) == len(allTableArray):
for i, v := range essai {
s := strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.17.4.3.1.1")
bytes := v.Value.([]byte)
macAddrTable[i] = oidMacAddr { s, string(bytes) }
allTableArray[i] = allTable { ptVlan1id: s, macAddr: bytes }
s = strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.17.4.3.1.2")
if s == allTableArray[i].ptVlan1id {
allTableArray[i].brPortNb = gosnmp.ToBigInt(v.Value)
}
}
Notice that by using for i, v := range essai syntax, you have access to both the index and the value without having to use essai[i] for the value.
Now your two loops can become just one, plus no embedded loops which are really hard to make sense of.
I Also recommend you work with slice instead of array. It's more flexible that way.
To help debug GO programs, I want to write two generic functions that will be called on entry and exit, which will print the values of input and output parameters respectively:
printInputParameters(input ...interface{})
printOutputParameters(output ...interface{})
Is there an equivalent of os.Args() for functions? I looked at runtime package and didn't find such functions.
For example lets say I have two functions with different input parameters and output parameters
func f1(int i, float f) (e error) {
... some code here
}
func f2(s string, b []byte) (u uint64, e error) {
.. some code here
}
I want to be able to do the following
func f1(int i, float f) (e error) {
printInputparameters( ? )
defer func() {
printOutputParameters( ? )
}()
... some code here
}
func f2(s string, b []byte) (u uint64, e error) {
printInputparameters( ? )
defer func() {
printOutputParameters( ? )
}()
... some code here
}
You cannot do this in Go since there is no way you can get the stack frame of the currently active function in the current goroutine. It is not impossible to do this as I'll show further below but the problem is that there is no public API to get this done reliably. That it can be done can be seen in the stack traces printed when a panic is raised: all values on the stack are dumped in that case.
Should you be interested in how the stack trace is actually generated then have a look at genstacktrace in the runtime package.
As for a solution to your problem, you can the source code parsing route as already suggested. If you feel adventurous, you can parse the stack trace provided by runtime.Stack. But beware, there are so many drawbacks that you will quickly realize that any solution is better than this one.
To parse the stack trace, just get the line of the previously called function (from the viewpoint of printInputParameters), get the name of that function and parse the parameter values according to the parameter types provided by reflection. Some examples of stack trace outputs of various function invocations:
main.Test1(0x2) // Test1(int64(2))
main.Test1(0xc820043ed5, 0x3, 0x3) // Test1([]byte{'A','B','C'})
main.Test1(0x513350, 0x4) // Test1("AAAA")
You can see that complex types (those which do not fit into a register) may use more than one 'parameter'. A string for example is a pointer to the data and the length. So you have to use the unsafe package to access these pointers and reflection to create values from this data.
If you want to try yourself, here's some example code:
import (
"fmt"
"math"
"reflect"
"runtime"
"strconv"
"strings"
"unsafe"
)
// Parses the second call's parameters in a stack trace of the form:
//
// goroutine 1 [running]:
// main.printInputs(0x4c4c60, 0x539038)
// /.../go/src/debug/main.go:16 +0xe0
// main.Test1(0x2)
// /.../go/src/debug/main.go:23
//
func parseParams(st string) (string, []uintptr) {
line := 1
start, stop := 0, 0
for i, c := range st {
if c == '\n' {
line++
}
if line == 4 && c == '\n' {
start = i + 1
}
if line == 5 && c == '\n' {
stop = i
}
}
call := st[start:stop]
fname := call[0:strings.IndexByte(call, '(')]
param := call[strings.IndexByte(call, '(')+1 : strings.IndexByte(call, ')')]
params := strings.Split(param, ", ")
parsedParams := make([]uintptr, len(params))
for i := range params {
iv, err := strconv.ParseInt(params[i], 0, 64)
if err != nil {
panic(err.Error())
}
parsedParams[i] = uintptr(iv)
}
return fname, parsedParams
}
func fromAddress(t reflect.Type, addr uintptr) reflect.Value {
return reflect.NewAt(t, unsafe.Pointer(&addr)).Elem()
}
func printInputs(fn interface{}) {
v := reflect.ValueOf(fn)
vt := v.Type()
b := make([]byte, 500)
if v.Kind() != reflect.Func {
return
}
runtime.Stack(b, false)
name, params := parseParams(string(b))
pidx := 0
fmt.Print(name + "(")
for i := 0; i < vt.NumIn(); i++ {
t := vt.In(i)
switch t.Kind() {
case reflect.Int64:
case reflect.Int:
// Just use the value from the stack
fmt.Print(params[pidx], ",")
pidx++
case reflect.Float64:
fmt.Print(math.Float64frombits(uint64(params[pidx])), ",")
pidx++
case reflect.Slice:
// create []T pointing to slice content
data := reflect.ArrayOf(int(params[pidx+2]), t.Elem())
svp := reflect.NewAt(data, unsafe.Pointer(params[pidx]))
fmt.Printf("%v,", svp.Elem())
pidx += 3
case reflect.String:
sv := fromAddress(t, params[pidx])
fmt.Printf("%v,", sv)
pidx += 2
case reflect.Map:
// points to hmap struct
mv := fromAddress(t,params[pidx])
fmt.Printf("%v,", mv)
pidx++
} /* switch */
}
fmt.Println(")")
}
Test:
func Test1(in int, b []byte, in2 int, m string) {
printInputs(Test1)
}
func main() {
b := []byte{'A', 'B', 'C'}
s := "AAAA"
Test1(2, b, 9, s)
}
Output:
main.Test1(2,[65 66 67],9,"AAAA",)
A slightly advanced version of this can be found on github:
go get github.com/githubnemo/pdump
To generically print your functions' arguments, you can do this:
func printInputParameters(input ...interface{}) {
fmt.Printf("Args: %v", input)
}
printInputParameters is a variadic function, and input is of type []interface{}.
I'm considering to call net.IP.String(), strings.Split(ip, "."), some code to calculate all the corner cases and finally net.ParseIP(s). Is there a better way to this?. Below is the code of my current implementation (no special case handled).
package main
import (
"fmt"
"net"
"strconv"
"strings"
)
func main() {
ip := net.ParseIP("127.1.0.0")
next, err := NextIP(ip)
if err != nil {
panic(err)
}
fmt.Println(ip, next)
}
func NextIP(ip net.IP) (net.IP, error) {
s := ip.String()
sa := strings.Split(s, ".")
i, err := strconv.Atoi(sa[2])
if err != nil {
return nil, err
}
i++
sa[3] = strconv.Itoa(i)
s = strings.Join(sa, ".")
return net.ParseIP(s), nil
}
Just increment the last octet in the IP address
ip := net.ParseIP("127.1.0.0")
// make sure it's only 4 bytes
ip = ip.To4()
// check ip != nil
ip[3]++ // check for rollover
fmt.Println(ip)
//127.1.0.1
That however is technically incorrect, since the first address in the 127.1.0.1/8 subnet is 127.0.0.1. To get the true "first" address, you will also need an IPMask. Since you didn't specify one, you could use DefaultMask for IPv4 addresses (for IPv6 you can't assume a mask, and you must provide it).
http://play.golang.org/p/P_QWwRIBIm
ip := net.IP{192, 168, 1, 10}
ip = ip.To4()
if ip == nil {
log.Fatal("non ipv4 address")
}
ip = ip.Mask(ip.DefaultMask())
ip[3]++
fmt.Println(ip)
//192.168.1.1
If all you need is to compute the next IP address, the function nextIP() below will do the trick.
Usage:
// output is 1.0.1.0
fmt.Println(nextIP(net.ParseIP("1.0.0.255"), 1))
nextIP():
func nextIP(ip net.IP, inc uint) net.IP {
i := ip.To4()
v := uint(i[0])<<24 + uint(i[1])<<16 + uint(i[2])<<8 + uint(i[3])
v += inc
v3 := byte(v & 0xFF)
v2 := byte((v >> 8) & 0xFF)
v1 := byte((v >> 16) & 0xFF)
v0 := byte((v >> 24) & 0xFF)
return net.IPv4(v0, v1, v2, v3)
}
Playground: https://play.golang.org/p/vHrmftkVjn2
Gist: https://gist.github.com/udhos/b468fbfd376aa0b655b6b0c539a88c03
I would test against CIDR after the IP has been incremented, so overflows don't change the expected subnet.
func incrementIP(origIP, cidr string) (string, error) {
ip := net.ParseIP(origIP)
_, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
return origIP, err
}
for i := len(ip) - 1; i >= 0; i-- {
ip[i]++
if ip[i] != 0 {
break
}
}
if !ipNet.Contains(ip) {
return origIP, errors.New("overflowed CIDR while incrementing IP")
}
return ip.String(), nil
}
I've encountered this problem just now, and I want to share my solution. It's not that efficient but solves the problem in a few lines.
func nextIP(ip net.IP) net.IP {
// Convert to big.Int and increment
ipb := big.NewInt(0).SetBytes([]byte(ip))
ipb.Add(ipb, big.NewInt(1))
// Add leading zeros
b := ipb.Bytes()
b = append(make([]byte, len(ip)-len(b)), b...)
return net.IP(b)
}
This is straightforward using the IPAddress Go library, works for both IPv4 and IPv6, and handles corner cases. Disclaimer: I am the project manager.
import (
"fmt"
"github.com/seancfoley/ipaddress-go/ipaddr"
)
func main() {
fmt.Println(increment("127.0.0.1"))
fmt.Println(increment("127.0.0.255"))
fmt.Println(increment("::1"))
fmt.Println(increment("255.255.255.255"))
}
func increment(addrString string) *ipaddr.IPAddress {
addr := ipaddr.NewIPAddressString(addrString).GetAddress()
return addr.Increment(1)
}
Output:
127.0.0.2
127.0.1.0
::2
<nil>
I am a Go beginner, coming from Ruby land.
In Ruby, you could do something like this.
Time.send("now") is equivalent to Time.now, as you are sending the message now to the object Time
Is there something similar in golang?
There is no built in way of calling an arbitrary function from a string in Go.
You can create something similar by registering functions to a map[string].
A working example:
package main
import "fmt"
var m = map[string]func(){
"now": func() { fmt.Println("The time is now") },
"then": func() { fmt.Println("Once upon a time") },
}
func main() {
cmd := "then"
m[cmd]()
}
play.golang.org
There is also the possibility of using reflection in order to call a method by name. You can look at the reflect package for MethodByName and Call. You can also check this Stackoverflow question.
As other suggested, you can do it yourself by mapping strings to functions, but the strong-typing nature of Go makes it difficult to translate .send directly into Go.
You can still use reflection if you really need to access a field or method by name:
import "reflect"
import "fmt"
type A struct {
Number int
}
func (a *A) Method(i int) int {
return a.Number + i;
}
func main() {
a := &A{Number: 1}
// Direct access
fmt.Printf("Direct -> Nb: %d, Nb + 2: %d\n", a.Number, a.Method(2));
v := reflect.ValueOf(*a)
vp := reflect.ValueOf(a)
field := v.FieldByName("Number")
meth := vp.MethodByName("Method")
args := []reflect.Value{reflect.ValueOf(2)}
// Reflection access
fmt.Printf("Reflect -> Nb: %d, Nb + 2: %d\n",
field.Interface().(int),
meth.Call(args)[0].Interface().(int))
}
Outputs:
Direct -> Nb: 1, Nb + 2: 3
Reflect -> Nb: 1, Nb + 2: 3
play.golang.org
Note however:
How cumbersome that is. Usually, performing a map as suggested by #ANisus is a more idiomatic way of doing
You still have to perform your conversions in the end.
Using the reflect packages changes your typed variable into more flexible Value objects, but these are very cumbersome to use in practice. It is usually better if you can find a way to express your intent without relying on reflection.
Also note that here, we had to use two Values, one for a (a pointer to A) for the method, and one for *a (a A structure) for the field. Trying to get a method defined with a pointer receiver with a non-pointer Value (or conversely, trying to obtain a field via a pointer Value) will result in a panic. More generally, due to the dynamic nature of reflected Values and its difference with the usual typed Go, expect a lot of convenience features (such as automatic referencing/dereferencing) to be absent on Values.
Also, expect quite a bit of runtime panics while debugging, as it is the only way for dynamic Value calls to fail !
Reference: the reflect package
No. Work your way through http://tour.golang.org/ and http://golang.org/doc/effective_go.html and you will have a proper understanding of how method invocation works.
Here is a working example using reflect
package main
import (
"fmt"
"os"
"reflect"
)
// Send sends a message to(calls a method of) obj, with args.
// The return value of the method call is set to ret and any error to err.
func Send(obj interface{}, method string, args ...interface{}) (ret []reflect.Value, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
objValue := reflect.ValueOf(obj)
argsValue := make([]reflect.Value, 0, len(args))
for _, arg := range args {
argsValue = append(argsValue, reflect.ValueOf(arg))
}
mtd := objValue.MethodByName(method)
if !mtd.IsValid() {
return nil, fmt.Errorf("%v does not have a method %v", reflect.TypeOf(obj), method)
}
ret = mtd.Call(argsValue)
return
}
// Then do some tests.
type A struct {
value int
}
func (a A) Value() int {
return a.value
}
func (a *A) SetValue(v int) {
a.value = v
}
func main() {
var (
ret []reflect.Value
err error
)
// StdOut.WriteString("Hello, World!\n")
_, err = Send(os.Stdout, "WriteString", "Hello, World!\n")
handleError(err)
var a = &A{100}
// ret = a.Value()
ret, err = Send(a, "Value")
handleError(err)
fmt.Printf("Return value is: %v\n", ret[0].Int())
// a.SetValue(200)
_, err = Send(a, "SetValue", 200)
handleError(err)
// ret = a.Value()
ret, err = Send(a, "Value")
handleError(err)
fmt.Printf("Return value is: %v", ret[0].Int())
}
func handleError(err error) {
if err != nil {
panic(err)
}
}
I based my code on this description of send.
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
http://play.golang.org/p/lXlzBf_fGZ
package main
import "strings"
type Klass struct{}
func (k Klass) Hello(args ...string) string {
return "Hello " + strings.Join(args, " ")
}
func (k Klass) Send(symbol func(Klass, ...string) string, args ...string) string {
return symbol(k, args...)
}
func main() {
k := new(Klass)
k.Send(Klass.Hello, "gentle", "readers") //=> "Hello gentle readers"
}
The big difference between the two is that Go's Send function is only implemented for Klass and only works on methods that take a variable number of strings as parameters and return a single string. This is because Go is a statically typed language where Ruby is dynamically typed. Go does support dynamic typing via the reflect library, but it is an unpleasant experience and not the way general Go code is meant to be written.
I'm trying to write functions that will allow me to marshal/unmarshal simple structs into byte arrays. I've succeeded in writing Marshal, with help from the kind folks at #go-nuts, but I'm running into trouble writing Unmarshal.
// Unmarshal unpacks the binary data and stores it in the packet using
// reflection.
func Unmarshal(b []byte, t reflect.Type) (pkt interface{}, err error) {
buf := bytes.NewBuffer(b)
p := reflect.New(t)
v := reflect.ValueOf(p)
for i := 0; i < t.NumField(); i++ {
f := v.Field(i)
switch f.Kind() {
case reflect.String:
// length of string
var l int16
var e error
e = binary.Read(buf, binary.BigEndian, &l)
if e != nil {
err = e
return
}
// read length-of-string bytes from the buffer
raw := make([]byte, l)
_, e = buf.Read(raw)
if e != nil {
err = e
return
}
// convert the bytes to a string
f.SetString(bytes.NewBuffer(raw).String())
default:
e := binary.Read(buf, binary.BigEndian, f.Addr())
if e != nil {
err = e
return
}
}
}
pkt = p
return
}
The problem with the code above is that the call to f.Addr() near the end is apparently trying to get the address of an unaddressable value.
If there is an alternative solution, I would appreciate that as well. Either way, any help would be much appreciated.
Thanks!
I think you should use
v := p.Elem() // Get the value that 'p' points to
instead of
v := reflect.ValueOf(p)
Working example with lots of assumptions and a trivial data format:
package main
import (
"fmt"
"reflect"
"strconv"
)
// example marshalled format. lets say that marshalled data will have
// four bytes of a formatted floating point number followed by two more
// printable bytes.
type m42 []byte
// example struct we'd like to unmarshal into.
type packet struct {
S string // exported fields required for reflection
F float64
}
// example usage
func main() {
var p packet
if err := Unmarshal(m42("3.14Pi"), &p); err == nil {
fmt.Println(p)
} else {
fmt.Println(err)
}
}
func Unmarshal(data m42, structPtr interface{}) error {
vp := reflect.ValueOf(structPtr)
ve := vp.Elem() // settable struct Value
vt := ve.Type() // type info for struct
nStructFields := ve.NumField()
for i := 0; i < nStructFields; i++ {
fv := ve.Field(i) // settable field Value
sf := vt.Field(i) // StructField type information
// struct field name indicates which m42 field to unmarshal.
switch sf.Name {
case "S":
fv.SetString(string(data[4:6]))
case "F":
s := string(data[0:4])
if n, err := strconv.ParseFloat(s, 64); err == nil {
fv.SetFloat(n)
} else {
return err
}
}
}
return nil
}
Appropriate alternative solutions would depend heavily on the real data you need to support.
I'm going to bet that the reason f.Addr() has the problem because it actually isn't addressable.
the reflect package Type object has a method that will tell you if the type is addressable called CanAddr(). Assuming the field is addressable if it's not a string is not always true. If the struct is not passed in as a pointer to a struct then it's fields won't be addressable. For more details about what is and isn't addressable see: http://weekly.golang.org/pkg/reflect/#Value.CanAddr which outlines the correct rules.
Essentially for your code to work I think you need to ensure you always call it with a pointer to a struct.