In Go, a function can only accept arguments of the types specified in the parameter list in the function definition. The variadic parameter language feature complicates that a bit, but it follows well-defined rules.
The function signature for fmt.Println
is:
func Println(a ...interface{}) (n int, err error)
Per the language specifiction,
The final incoming parameter in a function signature may have a type prefixed with .... A function with such a parameter is called variadic and may be invoked with zero or more arguments for that parameter.
This means you can pass Println
a list of arguments of interface{}
type. Since all types implement the empty interface, you can pass a list of arguments of any type, which is how you're able to call Println(1, "one", true)
, for example, without error. See the "Passing arguments to ... parameters" section of the language specification:
the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.
The part that's giving you trouble is right after that in the specification:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
flag.Args()
is type []string
. Since T
in Println
is interface{}
, []T
is []interface{}
. So the question comes down to whether a string slice value is assignable to a variable of interface slice type. You can easily test that in your go code by attempting an assignment, for example:
s := []string{}
var i []interface{}
i = s
If you attempt such an assignment, the compiler will output this error message:
cannot use s (type []string) as type []interface {} in assignment
And that's why you can't use the ellipsis after a string slice as an argument to fmt.Println
. It's not a bug, it's working as intended.
There are still lots of ways you can print flag.Args()
with Println
, such as
fmt.Println(flag.Args())
(which will output as [elem0 elem1 ...]
, per fmt package documentation)
or
fmt.Println(strings.Join(flag.Args(), ` `)
(which will output the string slice elements, each separated by a single space) using the Join function in the strings package with a string separator, for example.
go run test.go some test flags
), and it seemed to work when changingflags.Args()...
to justflag.Args()
(output is[some test flags]
, followed by the newline; also seemed to work with registering actual flags). Won't pretend to understand why, and Stephen's answer is way more informative anyway :) – Murdocca