Как передать массив множественного типа в одной функции

#go

#Вперед

Вопрос:

У меня есть несколько структур

 type Base struct {
    Id string
    Name string
    Code string
}
  
 type Country struct {
    Base
    ...
}
  
 type City struct {
    Base
    ...
}
  

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

Спасибо

Комментарии:

1. вы можете создать метод для типов, эти методы могут иметь одинаковое имя. но если country и city — это одна и та же структура, тогда зачем создавать 2 структуры?

2. вы могли бы попытаться заставить функцию принимать тип интерфейса []{}

3. @Pizzalord Каждая структура связана с Gorm, и иногда они представляют собой несколько дополнительных полей ! Что вы подразумеваете под методом создания для типов?

4. @SivaGuru Я пробовал, не работает для array -> Не удается использовать ‘предложение. Страны (введите []Country) как интерфейс типа []{}

5. @Clowning вы могли бы сделать функцию x (интерфейс массива{}) вместо x (интерфейс массива []{}), поскольку вы отправляете 1 интерфейс, который является массивом

Ответ №1:

Похоже, вы пытаетесь воссоздать наследование классов в Go. Go специально не использует наследование классов. Не пытайтесь воссоздать его. Я полагаю, вы думаете, что «Country — это база». Это неверно. Страна встраивает базу. Это не одно и то же. Это имеет значение для того, как вы называете вещи. В этом случае кажется, что «База» на самом деле является «метаданными местоположения», поэтому мы будем называть это так.

 type LocationMeta struct {
    id   string
    name string
    code string
}
  

И вам нужен интерфейс для работы со всеми типами местоположений.

 type Location interface {
    Id() string
    Name() string
    Code() string
}
  

Мы можем привести LocationMeta в соответствие с Location, хотя это, возможно, немного странно (являются ли метаданные действительно местоположением?). Но это работает.

 func (b LocationMeta) Id() string {
    return b.id
}

func (b LocationMeta) Name() string {
    return b.name
}

func (b LocationMeta) Code() string {
    return b.code
}
  

И мы можем встроить LocationMeta в город:

 type City struct {
    LocationMeta
}
  

И бесплатно, город теперь соответствует местоположению.

Тем не менее, обычно вы не утруждаете себя такого рода внедрением для такой маленькой вещи без собственной логики. Это действительно перебор; я просто демонстрировал это, потому что вы, похоже, этим пользуетесь. Обычно вы просто соответствуете каждому типу самостоятельно:

 type Country struct {
    id   string
    name string
    code string
}

func (c Country) Id() string {
    return c.id
}

func (c Country) Name() string {
    return c.name
}

func (c Country) Code() string {
    return c.code
}
  

Самое замечательное в Go то, что ему все равно, как вы соответствуете интерфейсу. Город и страна соответствуют местоположению совершенно по-разному, и это совершенно нормально.

Чтобы затем вы могли создать город:

 boston := City{LocationMeta{id: "bos", name: "Boston", code: "bos"}}
  

Видите, насколько это странно? Мы должны создать LocationMeta из-за встроенного объекта. Иногда это может стоить того (и невероятно мощно), но я бы, вероятно, сделал и City, и Country по-деревенски (без LocationMeta):

 us := Country{id: "us", name: "USA", code: "us"}
  

Но все равно, это оба местоположения, поэтому мы можем поместить их в срез:

 locations := []Location{boston, us}
  

И передать их вещам:

 func printLocations(locations []Location) {
    fmt.Println(locations)
}

printLocations(locations)
  

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

Игровая площадка, использующая встраивание для всего

Игровая площадка более типичного подхода с использованием только структур

Ответ №2:

я уже опубликовал это в комментариях, но вы можете сделать это

 func myfunc(in interface{}) {
    switch in.(type) {
    case []Country:
        // country logic here
    case []City:
        // city logic here
    }
}