Опциональные параметры в Go?
Можно ли в Go использовать необязательные параметры? Или мне просто нужно определить две разные функции с одинаковым именем, но с разным количеством аргументов?
5 ответ(ов)
Для достижения чего-то подобного опциональным параметрам в Go можно использовать вариадические аргументы. Функция фактически принимает срез значений любого заданного вами типа.
Вот пример:
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo() // Выводит: 0
foo(1) // Выводит: 1
foo(1, 2, 3) // Выводит: 3
}
В этом примере функция foo
принимает произвольное количество целых чисел. Внутри функции вы можете работать с параметрами, как со срезом, что позволяет вам легко манипулировать переданными аргументами. Это удобный способ добавления гибкости в вашу функцию, не требуя создания множества перегруженных версий.
Вы можете использовать структуру, которая включает параметры:
type Params struct {
a, b, c int
}
func doIt(p Params) int {
return p.a + p.b + p.c
}
// Вы можете вызвать функцию, не указывая все параметры
doIt(Params{a: 1, c: 9})
Главным преимуществом по сравнению с параметрами переменной длины (params ...SomeType
) является то, что вы можете использовать эту структурированную переменную с параметрами разных типов.
Вы можете передавать произвольные именованные параметры с помощью карты. Учтите, что если параметры имеют неоднородные типы, вам нужно будет использовать утверждение типов в формате aType = map[key].(*foo.type)
.
Вот пример кода:
type varArgs map[string]interface{}
func myFunc(args varArgs) {
arg1 := "default"
if val, ok := args["arg1"]; ok {
arg1 = val.(string)
}
arg2 := 123
if val, ok := args["arg2"]; ok {
arg2 = val.(int)
}
fmt.Println(arg1, arg2)
}
func Test_test() {
myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
В этом примере функция myFunc
принимает переменное количество аргументов в виде карты, где ключи — это названия параметров, а значения — это любые типы, представленные как interface{}
. Мы используем утверждения типов для получения значений аргументов с их предполагаемыми типами.
Кажется, я сильно запоздал с этой темой, но я искал способ сделать это лучше, чем тот, что я уже использую. Предложенное решение частично отвечает вашим требованиям, а также вводит концепцию необязательных аргументов.
package main
import "fmt"
type FooOpts struct {
// необязательные аргументы
Value string
}
func NewFoo(mandatory string) {
NewFooWithOpts(mandatory, &FooOpts{})
}
func NewFooWithOpts(mandatory string, opts *FooOpts) {
if opts != nil {
fmt.Println("Hello " + opts.Value)
} else {
fmt.Println("Hello")
}
}
func main() {
NewFoo("пожалуйста, заставьте это работать")
NewFooWithOpts("Пожалуйста, заставьте это работать", &FooOpts{Value: " Мир"})
}
Обновление 1:
Добавил функциональный пример, чтобы показать, как это работает.
Вы можете использовать указатели и оставлять их nil, если не хотите их использовать:
func getPosts(limit *int) {
if limit != nil {
// получить посты с ограничением
} else {
// получить все посты
}
}
func main() {
// получить посты, ограничивая до 2
limit := 2
getPosts(&limit)
// получить все посты
getPosts(nil)
}
Такой подход позволяет вам передавать nil
, когда ограничение не требуется, и использовать указатели, чтобы избежать передачи "магических" значений.
Существует ли цикл foreach в Go?
Как сопоставить любой символ на нескольких строках в регулярном выражении?
Отформатировать строку в Go без вывода?
Как присвоить строку массиву байтов
Есть ли способ получить доступ к приватным полям структуры из другого пакета?