20

Sorry for the basic question. I'd like to pass a slice as arguments to fmt.Sprintf. Something like this:

values := []string{"foo", "bar", "baz"}
result := fmt.Sprintf("%s%s%s", values...)

And the result would be foobarbaz, but this obviously doesn't work.

(the string I want to format is more complicated than that, so a simple concatenation won't do it :)

So the question is: if I have am array, how can I pass it as separated arguments to fmt.Sprintf? Or: can I call a function passing an list of arguments in Go?

moraes
  • 13,213
  • 7
  • 45
  • 59

4 Answers4

26

As you found out on IRC, this will work:

values := []interface{}{"foo", "bar", "baz"}
result := fmt.Sprintf("%s%s%s", values...)

Your original code doesn't work because fmt.Sprintf accepts a []interface{} and []string can't be converted to that type, implicitly or explicitly.

Evan Shaw
  • 23,839
  • 7
  • 70
  • 61
  • 1
    This is less practical in some use cases. For example, I'm trying to match an interface which takes a `...string` argument, so I can't change the type to `[]interface{}` without explicitly allocating a new slice and copying all of the elements over. – zstewart Jun 29 '15 at 18:40
  • Yes, that's true and unfortunate. In that case you have to figure out whether it's worth the allocate-and-copy or find another solution. – Evan Shaw Jun 30 '15 at 01:11
  • @EvanShaw what is the purpose of having `values...`? – Kasun Siyambalapitiya Oct 06 '17 at 11:42
  • `values...` is equivalent to `fmt.Sprintf("%s%s%s", "foo", "bar", "baz")`, while `values` is equivalent to `fmt.Sprintf("%s%s%s", []interface{}{"foo", "bar", "baz"})`. The latter is probably not what you want and will produce an error message at runtime. – Evan Shaw Oct 12 '17 at 19:59
4

If the format is strictly like what you asked, then the accepted answer is indeed the way to go.

Fyi, if it is for logging purposes where you simply want to print them, then another way is by using %v

values := []string{"foo", "bar", "baz"}
result := fmt.Sprintf("%v", values)
fmt.Println(result)

result:

[foo bar baz]

Go playground: https://go.dev/play/p/_fZrT9mMmdb

Yusril Maulidan Raji
  • 1,682
  • 1
  • 21
  • 46
0

if not use array, use args ...any

package main

import "fmt"

func main() {
    format := "%d,%d: %s"

    check(format, 4, 5, "hello")
}

func check(format string, args ...any) {

    fmt.Printf(format, args...)
}
Yan Chen
  • 53
  • 2
  • 7
-1

I think the issue with doing this is that the Sprintf won't work with unbounded length slices, so it's not practical. The number of format parameters must match the number of formatting directives. You will either have to extract them into local variables or write something to iterate the slice and concatenate the strings together. I'd go for the latter.

Deleted
  • 4,804
  • 1
  • 22
  • 17
  • 2
    I got an answer on IRC: it will with `values := []interface{}{"foo", "bar", "baz"}`. – moraes Aug 22 '11 at 11:49
  • 1
    I'm afraid on this one you are not even wrong. What is an "unbounded length slices"? There is no such thing in Go, all slices have a len() and a cap(). – uriel Aug 26 '11 at 19:08
  • i.e. the length is not known at compile time. I should be more clear. – Deleted Aug 27 '11 at 22:41