Дополнительные параметры?

Can Go имеют необязательные параметры? Или я могу просто определить две функции с тем же именем и другим числом аргументов?

Ответ 1

Go не имеет необязательных параметров и не поддерживает перегрузку метода:

Отправка метода упрощается, если он не нужно выполнять сопоставление типов, как Что ж. Опыт работы на других языках сказал, что с методы с тем же именем, но иногда были разные подписи полезно, но также может быть путают и хрупки на практике. Соответствие только по названию и требование согласованность в типах была крупной упрощение решения в стиле Go система.

Ответ 2

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

type Params struct {
  a, b, c int
}

func doIt(p Params) int {
  return p.a + p.b + p.c 
}

// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})

Ответ 3

Хорошим способом достижения чего-то вроде необязательных параметров является использование переменных переменных. Функция фактически получает срез любого типа, который вы указываете.

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

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

Ответ 4

Для произвольного, потенциально большого количества необязательных параметров, хорошая идиома заключается в использовании Функциональных опций.

Для вашего типа Foobar сначала напишите только один конструктор:

func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
  fb := &Foobar{}
  // ... (write initializations with default values)...
  for _, op := range options{
    err := op(fb)
    if err != nil {
      return nil, err
    }
  }
  return fb, nil
}

где каждый параметр является функцией, которая мутирует Foobar. Затем предоставите удобные способы для использования пользователем или создания стандартных параметров, например:

func OptionReadonlyFlag(fb *Foobar) error {
  fb.mutable = false
  return nil
}

func OptionTemperature(t Celsius) func(*Foobar) error {
  return func(fb *Foobar) error {
    fb.temperature = t
    return nil
  }
}

Игровая площадка

Для краткости вы можете указать имя типа параметров (Игровая площадка):

type OptionFoobar func(*Foobar) error

Если вам нужны обязательные параметры, добавьте их в качестве первых аргументов конструктора перед переменным options.

Основными преимуществами идиомы функциональных опций являются:

  • ваш API может расти со временем, не нарушая существующий код, потому что подпись constuctor остается прежней, когда нужны новые параметры.
  • он позволяет использовать прецедент по умолчанию как самый простой: никаких аргументов вообще!
  • он обеспечивает точное управление инициализацией сложных значений.

Эта техника была придумана Rob Pike, а также продемонстрирована Дейв Чейни.

Ответ 6

Нет - нет. На Перейти для программистов на С++,

Go не поддерживает функцию перегрузка и не поддерживает пользователя определенных операторов.

Я не могу найти одинаково ясное утверждение о том, что необязательные параметры не поддерживаются, но они также не поддерживаются.

Ответ 7

Вы можете инкапсулировать это довольно хорошо в func, подобном тому, что ниже.

package main

import (
        "bufio"
        "fmt"
        "os"
)

func main() {
        fmt.Println(prompt())
}

func prompt(params ...string) string {
        prompt := ": "
        if len(params) > 0 {
                prompt = params[0]
        }
        reader := bufio.NewReader(os.Stdin)
        fmt.Print(prompt)
        text, _ := reader.ReadString('\n')
        return text
}

В этом примере запрос по умолчанию имеет двоеточие и пробел перед ним.,.

: 

., однако вы можете переопределить это, предоставив параметр функции приглашения.

prompt("Input here -> ")

Это приведет к следующему приглашению.

Input here ->

Ответ 8

В итоге я использовал комбинацию структуры params и variadic args. Таким образом, мне не пришлось менять существующий интерфейс, который был использован несколькими службами, и моя служба смогла передать дополнительные параметры по мере необходимости. Пример кода на игровой площадке golang: https://play.golang.org/p/G668FA97Nu

Ответ 9

Я немного опаздываю, но если вам нравится свободный интерфейс, вы можете создать свои сеттеры для таких цепочек:

type myType struct {
  s string
  a, b int
}

func New(s string, err *error) *myType {
  if s == "" {
    *err = errors.New(
      "Mandatory argument `s` must not be empty!")
  }
  return &myType{s: s}
}

func (this *myType) setA (a int, err *error) *myType {
  if *err == nil {
    if a == 42 {
      *err = errors.New("42 is not the answer!")
    } else {
      this.a = a
    }
  }
  return this
}

func (this *myType) setB (b int, _ *error) *myType {
  this.b = b
  return this
}

И затем назовите его следующим образом:

func main() {
  var err error = nil
  instance :=
    New("hello", &err).
    setA(1, &err).
    setB(2, &err)

  if err != nil {
    fmt.Println("Failed: ", err)
  } else {
    fmt.Println(instance)
  }
}

Это похоже на Идиомы функциональных опций, представленные в ответе @Ripounet, и пользуется теми же преимуществами, но имеет некоторые недостатки:

  • Если произошла ошибка, она не будет отменена немедленно, поэтому она будет немного менее эффективной, если вы ожидаете, что ваш конструктор будет часто сообщать об ошибках.
  • Вам придется потратить строку, объявляющую переменную err и обнуляющую ее.

Существует, однако, небольшое преимущество, этот тип вызовов функций должен быть проще для встроенного компилятора, но я действительно не специалист.