Коротко — да, можно. В Go коллекция (слайс, массив, map и т.д.) по умолчанию однородна по типу элементов, но вы можете сделать её «гетерогенной», используя общий интерфейс, обычно пустой интерфейс interface{} (в Go1.18+ — алиас any).
Примеры.
1) Слайс различных значений через any/interface{}:
```go
package main
import "fmt"
func foo(value int) int { return value }
func main() {
col := []any{1, "two", 3.14, foo}
for _, v := range col {
switch t := v.(type) {
case int:
fmt.Println("int:", t)
case string:
fmt.Println("string:", t)
case float64:
fmt.Println("float64:", t)
case func(int) int:
fmt.Println("func result:", t(5))
default:
fmt.Printf("unknown: %T\n", v)
}
}
}
```
При извлечении значений нужно делать приведение типов (type assertion) или type switch.
2) map[string]any для JSON-подобных структур:
```go
m := map[string]any{
"id": 123,
"name": "Alice",
"tags": []any{"go", "programming"},
}
```
3) Предпочтительный способ для полиморфизма — общий интерфейс с методами:
```go
type Speaker interface {
Speak() string
}
type Dog struct{}
func (Dog) Speak() string { return "woof" }
type Cat struct{}
func (Cat) Speak() string { return "meow" }
arr := []Speaker{Dog{}, Cat{}}
```
Так вы сохраняете типобезопасность и не нуждаетесь в приведениях, если вам важна общая поведение.
4) Generics (Go 1.18+) не дают «встроенного» способа хранить в одной коллекции разные типы одновременно, если только вы не выберете обобщённый параметр как интерфейс (например any) или интерфейс-объединение типов. Например, type Slice[T any] []T — при инстанциации T фиксируется, поэтому все элементы будут одного конкретного T.
Итого:
- Да, можно через interface{}/any или через интерфейс с методами.
- Минус interface{} — теряется проверка типов на этапе компиляции, нужны приведения/type switch.
- Лучше проектировать API с общим интерфейсом или с корректной структурой данных, вместо широкого использования any, если вам важна безопасность типов.