Необязательные параметры?

Если вы объявите Filter как

public class Filter<T extends Iterable>

, тогда

import java.util.Iterator;

public enum TimePeriod implements Iterable {
    ALL("All"),
    FUTURE("Future"),
    NEXT7DAYS("Next 7 Days"),
    NEXT14DAYS("Next 14 Days"),
    NEXT30DAYS("Next 30 Days"),
    PAST("Past"),
    LAST7DAYS("Last 7 Days"),
    LAST14DAYS("Last 14 Days"),
    LAST30DAYS("Last 30 Days");

    private final String name;

    private TimePeriod(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    public Iterator<TimePeriod> iterator() {
        return new Iterator<TimePeriod>() {

            private int index;

            @Override
            public boolean hasNext() {
                return index < LAST30DAYS.ordinal();
            }

            @Override
            public TimePeriod next() {
                switch(index++) {
                    case    0   : return        ALL;
                    case    1   : return        FUTURE;
                    case    2   : return        NEXT7DAYS;
                    case    3   : return        NEXT14DAYS;
                    case    4   : return        NEXT30DAYS;
                    case    5   : return        PAST;
                    case    6   : return        LAST7DAYS;
                    case    7   : return        LAST14DAYS;
                    case    8   : return        LAST30DAYS;
                    default: throw new IllegalStateException();
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

И использование довольно просто:

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        Iterator<TimePeriod> it = selectedOption.iterator();
        while(it.hasNext()) {
            availableOptions.add(it.next());
        }
    }
}
377
задан tgogos 30 August 2017 в 09:52
поделиться

11 ответов

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

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

372
ответ дан Andrew Hare 30 August 2017 в 09:52
поделиться

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

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})
141
ответ дан deamon 30 August 2017 в 09:52
поделиться

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

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

func main() {
    foo()
    foo(1)
    foo(1,2,3)
}
182
ответ дан awqueous 30 August 2017 в 09:52
поделиться

Нет - ни то, ни другое. Согласно Go для программистов на C ++ документы,

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

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

5
ответ дан Jonathan Leffler 30 August 2017 в 09:52
поделиться

Ни необязательные параметры, ни перегрузка функций не поддерживаются в Go. Go поддерживает переменное число параметров: Передача аргументов в ... parameters

16
ответ дан peterSO 30 August 2017 в 09:52
поделиться

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

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 ->
4
ответ дан Jam Risser 30 August 2017 в 09:52
поделиться

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

2
ответ дан Adriana 30 August 2017 в 09:52
поделиться

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

2
ответ дан BaSO4 30 August 2017 в 09:52
поделиться

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

Для вашего типа 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
  }
}

Playground

Для краткости вы можете дать имя типу из опций ( Playground ):

type OptionFoobar func(*Foobar) error

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

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

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

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

101
ответ дан frohlichcortezh 30 August 2017 в 09:52
поделиться

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

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, и обладает теми же преимуществами, но имеет некоторые недостатки:

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

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

1
ответ дан VinGarcia 30 August 2017 в 09:52
поделиться

Можно передать произвольные именованные параметры с картой.

type varArgs map[string]interface{}

func myFunc(args varArgs) {

    arg1 := "default" // optional default value
    if val, ok := args["arg1"]; ok {
        // value override or other action
        arg1 = val.(string) // runtime panic if wrong type
    }

    arg2 := 123 // optional default value
    if val, ok := args["arg2"]; ok {
        // value override or other action
        arg2 = val.(int) // runtime panic if wrong type
    }

    fmt.Println(arg1, arg2)
}

func Test_test() {
    myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
2
ответ дан 22 November 2019 в 23:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: