В Go функция может принимать аргументы только тех типов, которые указаны в списке параметров в определении функции. Функция языка с вариативными параметрами немного усложняет это, но следует четко определенным правилам.
Сигнатура функции fmt.Println
:
func Println(a ...interface{}) (n int, err error)
В зависимости от языковой специфики ,
Последний входящий параметр в сигнатуре функции может иметь тип с префиксом .... Функция с таким параметром называется вариативной и может быть вызвана с нулем или более аргументов для этого параметра.
Это означает, что вы можете передать Println
список аргументов interface{}
типа. Поскольку все типы реализуют пустой интерфейс, вы можете передать список аргументов любого типа, Println(1, "one", true)
например, таким образом вы можете вызывать его без ошибок. См. Раздел «Передача аргументов в ... параметры» спецификации языка:
переданное значение представляет собой новый фрагмент типа [] T с новым базовым массивом, последовательные элементы которого являются фактическими аргументами, которые все должны быть присвоены T.
Часть, которая вызывает у вас проблемы, находится сразу после этого в спецификации:
Если последний аргумент может быть назначен типу фрагмента [] T, он может быть передан без изменений в качестве значения параметра ... T, если за аргументом следует .... В этом случае новый фрагмент не создается.
flag.Args()
это тип []string
. Поскольку T
in Println
is interface{}
, []T
is []interface{}
. Таким образом, вопрос сводится к тому, можно ли присвоить строковое значение среза переменной типа среза интерфейса. Вы можете легко проверить это в своем коде Go, попробовав присвоение, например:
s := []string{}
var i []interface{}
i = s
Если вы попытаетесь выполнить такое назначение, компилятор выдаст это сообщение об ошибке:
cannot use s (type []string) as type []interface {} in assignment
Вот почему вы не можете использовать многоточие после отрезка строки в качестве аргумента fmt.Println
. Это не ошибка, работает как задумано.
Есть еще много способов , вы можете напечатать flag.Args()
с Println
, например,
fmt.Println(flag.Args())
(который будет выводиться как [elem0 elem1 ...]
в документации пакета fmt )
или
fmt.Println(strings.Join(flag.Args(), ` `)
(который будет выводить элементы среза строки, каждый из которых разделен одним пробелом), например, с помощью функции Join в пакете строк с разделителем строк.
go run test.go some test flags
), и, похоже, он работал при измененииflags.Args()...
на простоflag.Args()
(вывод[some test flags]
, за которым следует новая строка; также, похоже, работал с регистрацией фактических флагов). Не буду делать вид, что понимает почему, и ответ Стивена в любом случае более информативен :)