Golang pass nil как необязательный аргумент функции?

В Golang http.NewRequest имеет следующую спецификацию:

func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

Однако я могу передать nil в качестве опции body, если я не хочу передавать body объекту io.Reader, например так:

req, err := http.NewRequest("GET", "http://www.blahblah.org", nil)

Как мне реализовать эту функцию в моем коде? У меня есть функция, которую я хочу передать необязательное строковое значение, чтобы оно могло перелистывать результаты API, однако, если я передаю nil в строковый ввод, я получаю это:

. /snippets.go:32: невозможно преобразовать ноль в строку типа

Параметры для моей функции выглядят так:

func getChallenges(after string) ([]challenge, string, error)

Ответ 1

Go не имеет "необязательных" аргументов в качестве общепринятой концепции в других языках; nil - это просто нулевое значение для интерфейса (в данном случае io.Reader).

Эквивалентное нулевое значение для строки является пустой строкой:

getChallenges("")

Если вы хотите принять 0 или более аргументов одного и того же типа аргумента, используйте синтаксис variadic:

func getChallenges(after ...string) ([]challenge, string, error)

Ответ 2

Вы можете изменить свою функцию для получения значения указателя, например:

func getChallenges(after *string) ([]challenge, string, error)

Затем вы можете передать nil в качестве аргумента. Но не забудьте проверить значение after для nil внутри вашей функции до разыменования, или вы получите исключение nil-указателя:

func getChallenges(after *string) ([]challenge, string, error) {
    if after == nil {
        // No value specified
    } else {
        fmt.Printf("After: %s\n", *after) // Note pointer dereferencing with "*"
    }
    // ...
}

Другая опция:

Просто используйте две функции:

func getChallenges(after string) {}

func getAllChallenges() {
    return getChallenges(/* some default value here */)
}

Ответ 3

вы можете использовать оператор эллипса для отправки необязательных параметров. Не пропускайте ничего в необязательном параметре и не проверяйте длину параметра. он должен решить вашу проблему

func foo(params ...int) {
   fmt.Println(len(params))
}

func main() {
    foo()
    foo(1)
    foo(1,2,3)
}

Ответ 4

Вы можете использовать отражение. Фактически io.Reader является интерфейсом.

Итак, вы можете определить подпись типа func getChallenges(after interface{}) ([]challenge, string, error)

interface {} - пустой интерфейс, который является интерфейсом для чего-либо.

Но я предлагаю вам использовать синтаксис args... для передачи фрагмента, см. реализацию fmt.Printf для использования, потому что если вы не передаете нить, то срез len равен 0 и это позволит избежать отражения, которое я считаю слишком тяжелым для вашей функции.