Если вы объявите 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());
}
}
}
Go не имеет необязательных параметров и не поддерживает перегрузку метода :
Диспетчеризация метода упрощается, если ему не нужно также выполнять сопоставление типов. Опыт работы с другими языками показал нам, что наличие различных методов с одинаковыми именами, но разными сигнатурами иногда полезно, но на практике это может быть также запутанным и хрупким. Совпадение только по имени и требование согласованности типов было основным упрощающим решением в системе типов Go.
Вы можете использовать структуру, которая включает параметры:
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})
Хороший способ получить что-то вроде необязательных параметров - это использовать переменные аргументы. Функция фактически получает фрагмент любого типа, который вы укажете.
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
Нет - ни то, ни другое. Согласно Go для программистов на C ++ документы,
Go не поддерживает перегрузку функций и не поддерживает определяемые пользователем операторы.
Я не могу найти столь же ясное утверждение, что необязательные параметры не поддерживаются, но они также не поддерживаются.
Ни необязательные параметры, ни перегрузка функций не поддерживаются в Go. Go поддерживает переменное число параметров: Передача аргументов в ... parameters
Вы можете довольно красиво описать это в функции, аналогичной приведенной ниже.
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 ->
В итоге я использовал комбинацию структуры params и variadic args. Таким образом, мне не пришлось менять существующий интерфейс, который использовался несколькими сервисами, и мой сервис мог передавать дополнительные параметры по мере необходимости. Пример кода на детской площадке Голанга: https://play.golang.org/p/G668FA97Nu
Язык Go не поддерживает перегрузку методов, но вы можете использовать переменные аргументы точно так же, как необязательные параметры, также вы можете использовать интерфейс {} в качестве параметра, но это не очень хороший выбор.
Для произвольного, потенциально большого числа необязательных параметров, хорошая идиома - использовать Функциональные опции .
Для вашего типа 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 ):
type OptionFoobar func(*Foobar) error
Если вам нужны обязательные параметры, добавьте их в качестве первых аргументов конструктора перед переменным options
.
Основными преимуществами идиомы Функциональные опции являются:
Этот метод был придуман Робом Пайком , а также продемонстрирован Дейвом Чейни .
Я немного опаздываю, но если вам нравится свободный интерфейс, вы можете создать сеттеры для цепных вызовов следующим образом:
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
и обнуляющую ее. Однако есть небольшое преимущество: вызовы функций такого типа должны быть проще для встроенного компилятора, но я действительно не специалист.
Можно передать произвольные именованные параметры с картой.
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})
}