4

The following code

package main

import "strings"
import "fmt"

type Foo string

const (
    Bar    Foo = "bar"
    Snafu      = "snafu"
    Foobar     = "foobar"
)

var Foos = []Foo{Bar, Snafu, Foobar}

func main() {
    fmt.Println("Foos: " + strings.Join(Foos, ","))
}

Produces this error:

./test.go:17: cannot use Foos (type []Foo) as type []string in argument to strings.Join

This makes sense since Foo is not string but it is derived from string. Is there any way to coerce the "[]Foo" to "[]string" without copying?

AlphaGeek
  • 383
  • 2
  • 11

2 Answers2

5

Pretty much the best and only way to do it is to loop over the slice of Foo objects as in (causing a copy):

func main() {
    results := make([]string, 0, len(Foos))
    for _, r := range Foos{
       results = append(results, string(r))
    }
    fmt.Println("Foos: " + strings.Join(results, ","))
}

Unfortunately as of this time Go does not support the concept type coercion and requires a copy. As an alternative you can type alias []Foo and add a Stringer method to it therefore encapsulating such details as in: http://play.golang.org/p/FuOoLNrCvD

See the following for a similar question: Cannot convert []string to []interface {}

OneOfOne
  • 95,033
  • 20
  • 184
  • 185
Ralph Caraveo
  • 10,025
  • 7
  • 40
  • 52
  • 1
    `results := make([]string, 0)` should be `results := make([]string, len(Foos))` – OneOfOne Jan 19 '15 at 19:31
  • 1
    @OneOfOne I thought the same but in fact using 'results := make([]string, len(Foos))' would introduce a bug. That's because this initialization will make an array full of nils. You then append to this array. So you get 'k x nil' cells at the start followed by the results. I can see your point though - we'll need to change the code inside the for loop like so: 'results[i] = string(r)' <- this will replace the nils with the correct values for each cell. – XDS Sep 23 '21 at 14:01
  • @XDS `results := make([]string, 0, len(Foos)`, updated the answer. – OneOfOne Oct 08 '21 at 20:30
0

You can use https://github.com/ledongthuc/goterators#map that I created to reuse aggregate & transforms functions.

enter image description here

package main

import (
    "fmt"
    "strings"

    "github.com/ledongthuc/goterators"
)

type Foo string

const (
    Bar    Foo = "bar"
    Snafu      = "snafu"
    Foobar     = "foobar"
)

var Foos = []Foo{Bar, Snafu, Foobar}

func main() {
    strs := goterators.Map(Foos, func(item Foo) string {
        return string(item)
    })
    fmt.Println("Foos: " + strings.Join(strs, ","))
}

Or if you want an optimized way, you can use Reduce

enter image description here

package main

import (
    "fmt"

    "github.com/ledongthuc/goterators"
)

type Foo string

const (
    Bar    Foo = "bar"
    Snafu      = "snafu"
    Foobar     = "foobar"
)

var Foos = []Foo{Bar, Snafu, Foobar}

func main() {
    joinStr := goterators.Reduce(Foos, "", func(previous string, current Foo, index int, list []Foo) string {
        if len(previous) == 0 {
            return string(current)
        }
        return previous + "," + string(current)
    })
    fmt.Println("Foos: " + joinStr)
}

They are required go 1.18 to use that support generic + dynamic type you want to use with.

Le Dong Thuc
  • 195
  • 1
  • 6
  • 1
    When linking to your own site or content (or content that you are affiliated with), you [must disclose your affiliation _in the answer_](/help/promotion) in order for it not to be considered spam. Having the same text in your username as the URL or mentioning it in your profile is not considered sufficient disclosure under Stack Exchange policy. – cigien Jan 03 '22 at 12:11
  • thanks for your reply. Will update it! – Le Dong Thuc Jan 03 '22 at 12:30