DEV Community

loading...

Learning Golang (some rough notes) - S01E05 - Interfaces

rmoff profile image Robin Moffatt Originally published at rmoff.net Updated on ・4 min read

👉A Tour of Go: Exercise: Stringers

I quite enjoyed this one, even though I still had to Google for some help. I got that I needed a function to implement the String() method for IPAddr (which is there in the help text too but I didn't notice, which goes to show I should spend longer reading the questions)

func (i IPAddr) String() string {

}

Within this I needed to take the four parts of the IP address and concatenate them with a . separator. Feeling rather proud of myself I came up with this which nicely handled each part of the IP address:

func (i IPAddr) String() string {
    a := ""
    for v := range i {
        a = a + v
    }
    return a
}


./prog.go:15:9: invalid operation: a + v (mismatched types string and int)

So let's try casting the type:

func (i IPAddr) String() string {
    a := ""
    for v := range i {
        a = a + string(v)
    }
    return a
}

This executed successfully, but didn't work:

So let's add some debug:

func (i IPAddr) String() string {
    a := ""
    for v := range i {
        fmt.Printf("Value: %v %vn", v, string(v))
        a = a + string(v)
    }
    return a
}
Value:
Value: 
Value: 
Value: 
loopback: 

So the value is showing as empty, which is odd, because we know it's there. Let's try more debug:

func (i IPAddr) String() string {
    a := ""
    for v := range i {
        fmt.Printf("value: %v tstring(value): %vn", v,  string(v))
        a = a + string(v)
    }
    return a
}
value: 0    string(value):
value: 1    string(value): 
value: 2    string(value): 
value: 3    string(value): 

OK, so the value we're getting isn't the IP address pieces… because we made a mistake in the for statement and we're getting the index, not the value. We're also getting a blank for the string, but we'll worry about that in a moment. Let's fix the for statement first. Using the underscore we can ignore the index and store the actual value in v:

func (i IPAddr) String() string {
    a := ""
    for _, v := range i {
        fmt.Printf("value: %v tstring(value): %vn", v,  string(v))
        a = a + string(v)
    }
value: 127  string(value): 
value: 0    string(value):
value: 0    string(value):
value: 1    string(value): 

We're getting somewhere.

What about this pesky blank string though when we try to cast the integer to a string? Courtesy of 6 Tips for Using Strings in Go and specifically the Convert ints (or any data type) into strings section I realised that string() wasn't the way to do it. What string() is doing is returning the ASCII character of the given value. Check out the output if I bump up the value in the string value in the Printf:

func (i IPAddr) String() string {
    a := ""
    for _, v := range i {
        fmt.Printf("value: %v tstring(value+64): %vn", v,  string(v+64))
        a = a + string(v)
    }
    return a
}
value: 127  string(value+64): ¿
value: 0    string(value+64): @
value: 0    string(value+64): @
value: 1    string(value+64): A

Maybe this was mentioned in the Tour and I missed it, but in doing the type conversion I'd referred back to Type conversions and it's not covered there. So instead of string() we can use strconv or Sprintf:

func (i IPAddr) String() string {
    a := ""
    for _, v := range i {
        fmt.Printf("value: %v tfmt.Sprintf(value): %vn", v, fmt.Sprintf("%d",v))
        a = a + string(v)
    }
    return a
}
value: 127  fmt.Sprintf(value): 127
value: 0    fmt.Sprintf(value): 0
value: 0    fmt.Sprintf(value): 0
value: 1    fmt.Sprintf(value): 1

Now we're getting somewhere! Let's use this Sprintf in building the a variable too, and add in a . in the format string:

func (i IPAddr) String() string {
    a := ""
    for _, v := range i {
        a = a + fmt.Sprintf("%d.",v)
    }
    return a
}

Look at that! We're nearly there. Just the trailing . to get rid of now, which a perusal of the strings package turns up a function TrimRight that should do the trick:

func (i IPAddr) String() string {
    a := ""
    for _, v := range i {
        a = a + fmt.Sprintf("%d.",v)
    }
    return strings.TrimRight(a,".")
}

So the final code looks like this:

package main

import (
    "fmt"
    "strings"
)

type IPAddr [4]byte

func (i IPAddr) String() string {
    a := ""
    for _, v := range i {
        a = a + fmt.Sprintf("%d.",v)
    }
    return strings.TrimRight(a,".")
}


func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %vn", name, ip)
    }
}
loopback: 127.0.0.1
googleDNS: 8.8.8.8

Discussion (0)

pic
Editor guide