Marty Wallace
Marty Wallace

Reputation: 35734

Golang - mapping an variable length array to a struct

I have a struct as follows:

type MyStruct struct {
   Part1 string
   Part2 string
   Part3 string
}

I have a string separated by slashes that I want to map to this:

part1/part2/part3

However, the string may only contain 1 part such as part1 or two parts such as part1/part2

if any part is missing it much be mapped as an empty string.

I am very new to go so wondering what the best way to achieve this is. Typically i would split the string and check the length to know what to do. In go is there a more elegant way to do this?

Upvotes: 3

Views: 3062

Answers (4)

Mike
Mike

Reputation: 1811

Expanding on dyoo's answer with shorter syntax and renamed types as I bypassed it for these two reasons, however it is the most extensible and reliable solution. The real benefit comes if you need to change from 3 to n elements, all that is required is a change to your struct definition and initialisation. StrSlice type is also very reusable when ever default values are required for a slice of strings.

package main

import (
    "fmt"
    "strings"
)

type MyStruct struct {
    Part1 string
    Part2 string
    Part3 string
}

type StrSlice []string

func (s StrSlice) Get(i int) string {
    if i >= 0 && i < len(s) {
        return s[i]
    }
    return ""
}

func main() {

    str := "part1/part2/part3"
    slice := StrSlice(strings.Split(str, "/"))
    parts := MyStruct{slice.Get(0),slice.Get(1),slice.Get(2)}
    fmt.Println(parts)

}

Upvotes: 0

zzzz
zzzz

Reputation: 91193

package main

import (
    "fmt"
    "strings"
)

type MyStruct struct {
    Part1 string
    Part2 string
    Part3 string
}

func (m *MyStruct) set(s string) *MyStruct {
    p := []*string{&m.Part1, &m.Part2, &m.Part3}
    for i, v := range strings.Split(s+"//", "/")[:3] {
        *p[i] = v
    }
    return m
}

func main() {
    var v MyStruct
    fmt.Printf("%#v\n", v.set("foo"))
    fmt.Printf("%#v\n", v.set(""))
    fmt.Printf("%#v\n", v.set("bar/baz"))
    fmt.Printf("%#v\n", v.set("alpha//omega"))
    fmt.Printf("%#v\n", v.set("/var/mail"))
}

Playground


Output:

&main.MyStruct{Part1:"foo", Part2:"", Part3:""}
&main.MyStruct{Part1:"", Part2:"", Part3:""}
&main.MyStruct{Part1:"bar", Part2:"baz", Part3:""}
&main.MyStruct{Part1:"alpha", Part2:"", Part3:"omega"}
&main.MyStruct{Part1:"", Part2:"var", Part3:"mail"}

Upvotes: 4

dyoo
dyoo

Reputation: 12003

Here's a version of peterSO's solution that uses a wrapper to help simplify the logic.

package main

import (
    "fmt"
    "strings"
)

type Wrap []string

func (w Wrap) Get(i int) string {
    if 0 <= i && i < len(w) {
        return w[i]
    }
    return ""
}

type MyStruct struct {
    Part1 string
    Part2 string
    Part3 string
}

func main() {
    str := "part1/part2/part3"
    split := Wrap(strings.Split(str, "/"))
    var parts MyStruct
    parts.Part1 = split.Get(0)
    parts.Part2 = split.Get(1)
    parts.Part3 = split.Get(2)
    fmt.Println(parts)

    str = "part1/part2"
    split = Wrap(strings.Split(str, "/"))
    parts = MyStruct{}
    parts.Part1 = split.Get(0)
    parts.Part2 = split.Get(1)
    parts.Part3 = split.Get(2)
    fmt.Println(parts)
}

Upvotes: 4

peterSO
peterSO

Reputation: 166529

For example,

package main

import (
    "fmt"
    "strings"
)

type MyStruct struct {
    Part1 string
    Part2 string
    Part3 string
}

func main() {
    str := "part1/part2/part3"
    split := strings.Split(str, "/")
    var parts MyStruct
    if len(split) > 0 {
        parts.Part1 = split[0]
        if len(split) > 1 {
            parts.Part2 = split[1]
            if len(split) > 2 {
                parts.Part3 = split[2]
            }
        }
    }
    fmt.Println(parts)
}

Output:

{part1 part2 part3}

Upvotes: 1

Related Questions