Is there a way to use strings.Join on a slice of structs?

4,360 views
Skip to first unread message

Robert Snedegar

unread,
Jun 14, 2011, 10:36:37 PM6/14/11
to golan...@googlegroups.com
If I have a type that has a String(), and I want to pass a slice of it
to strings.Join for easy printing, is there a way to convert it to be
a []string, or do I need to write my own copy of Join?

package pizza

import (
"fmt"
"strings"
)

type Topping int32
const (
CHEESE Topping = iota
PEPPERONI
MUSHROOMS
)

func (t Topping) String() string {
switch {
case t == CHEESE:
return "Cheese"
case t == PEPPERONI:
return "Pepperoni"
case t == MUSHROOMS:
return "Mushrooms"
}
return "?"
}

type Pizza struct {
size int32
toppings []Topping
}

func (p *Pizza) String() string {
return strings.Join(p.toppings, ",")
}

func main() {
p := &Pizza{14, []Topping{CHEESE, PEPPERONI}}
fmt.Println(p)
}


- Robert

Steven Blenkinsop

unread,
Jun 14, 2011, 11:18:05 PM6/14/11
to golan...@googlegroups.com

On Jun 14, 2011, at 10:36 PM, Robert Snedegar <vik...@gmail.com> wrote:

> If I have a type that has a String(), and I want to pass a slice of it
> to strings.Join for easy printing, is there a way to convert it to be
> a []string, or do I need to write my own copy of Join?

Easiest way to turn a []Toppings into a []string is just to use a loop:

strs := make([]string, len(p.toppings))
for i, v := range p.toppings {
strs[i] = v.String()
}
return strings.Join(strs, ", ")

peterGo

unread,
Jun 15, 2011, 11:28:30 AM6/15/11
to golang-nuts
Robert,

Don't you want a Strings method for type Toppings? For example,

package main

import (
"fmt"
"strconv"
)

type Topping int32

const (
Cheese Topping = iota
Pepperoni
Mushrooms
)

func (t Topping) String() string {
switch {
case t == Cheese:
return "Cheese"
case t == Pepperoni:
return "Pepperoni"
case t == Mushrooms:
return "Mushrooms"
}
return "?"
}

type Toppings []Topping

func (t Toppings) String() string {
s := "["
for _, t := range t {
if len(s) > 1 {
s += " "
}
s += t.String()
}
s += "]"
return s
}

type Pizza struct {
size int32
toppings Toppings
}

func (p *Pizza) String() string {
return "{" + strconv.Itoa(int(p.size)) + " " + p.toppings.String() +
"}"
}

func main() {
p := &Pizza{14, []Topping{Cheese, Pepperoni}}
fmt.Println(p)
}

Output:
{14 [Cheese Pepperoni]}

Peter

Robert Snedegar

unread,
Jun 15, 2011, 2:08:30 PM6/15/11
to peterGo, golang-nuts
I could make the slice of enums a separate type and implement a
Strings method on that, but then I still have to do that for every one
I create. More so, I was hoping that there would be an easier way of
passing a slice of anythings that have a String() method or func to
that Join and it would work.

Maybe create an interface StringJoinable whose only method is String()
and by implementing String for any type, they can be passed to
strings.SuperJoin([]StringJoinable)?

Nigel Tao

unread,
Jun 15, 2011, 8:33:03 PM6/15/11
to Robert Snedegar, peterGo, golang-nuts
On 16 June 2011 04:08, Robert Snedegar <vik...@gmail.com> wrote:
> Maybe create an interface StringJoinable whose only method is String()
> and by implementing String for any type, they can be passed to
> strings.SuperJoin([]StringJoinable)?

Even if Topping implements a Stringer interface, a []Topping won't be
a []Stringer, as they have different memory layouts. For more
background, read:
http://research.swtch.com/2009/11/go-data-structures.html
http://research.swtch.com/2009/12/go-data-structures-interfaces.html

In your case, I think that the thing to do is to write your own copy
of Join, whether as a standalone function or as a method on a
[]Topping type.

Reply all
Reply to author
Forward
0 new messages