Я использую Go, и у меня есть фабричная функция, которая возвращает объекты разных типов в зависимости от запрошенного идентификатора:
func NewObject(id string) interface{} {
switch id {
case "truck":
return Truck{}
case "car":
return Car{}
....
}
}
Вот соответствующие типы структур:
type Truck struct {
Foo string
}
type Car struct {
Bar string
}
Как видите, у Truck и Car нет ничего общего. Проблема возникает из-за того, что мне теперь приходится иметь дело со слишком широким типом interface{}
при вызове NewObject(..)
. Я знаю, что есть дженерики, но для этого потребуется сохранить список всех поддерживаемых типов в ограничениях типов, что усложнит мою кодовую базу.
В основном я ищу способ использовать здесь наследование, которое Go, конечно, не поддерживает. Какая была бы альтернатива?
Это хорошая идея, маркерный интерфейс. Я попробую это. Спасибо!
Я не понимаю, что именно вы спрашиваете. Если Truck
и Car
не имеют ничего общего, то как interface{}
может быть слишком широким типом? И как "наследование" (вы, наверное, имеете в виду особый способ сделать это в другом языке) может решить это, если у них нет ничего общего?
NewObject(..)
функция может быть реализована с поддержкой дженериков. Вам не нужно хранить список всех поддерживаемых типов в ограничениях типов.
func NewObject[T any](id string) T {
var vehicle any
switch id {
case "truck":
vehicle = Truck{
Foo: "foo",
}
case "car":
vehicle = Car{
Bar: "bar",
}
}
if val, ok := vehicle.(T); ok {
return val
}
var otherVehicle T
fmt.Printf("Not implemented. Returning with default values for \"%v\"\n", id)
return otherVehicle
}
Вы можете увидеть полный пример здесь.
Это то, что я наконец использовал, большое спасибо!
у меня странный пример
Этот пример вернет construct of struct
Надеюсь, это вдохновит вас
package main
import (
"fmt"
)
type testA struct {
a uint
}
type testB struct {
b string
}
var mp map[string]func(...interface{}) interface{} = map[string]func(...interface{}) interface{}{
"struct1": func(para ...interface{}) interface{} {
return &testA{
a: para[0].(uint),
}
},
"struct2": func(para ...interface{}) interface{} {
return &testB{
b: para[0].(string),
}
},
}
func NewSpecial(type_check_str string) func(...interface{}) interface{} {
if val, ok := mp[type_check_str]; ok {
return val
}
return nil
}
func main() {
test1 := NewSpecial("struct1")(uint(5))
test2 := NewSpecial("struct2")("It's Ok?")
fmt.Println(test1)
fmt.Println(test2)
}
Большое спасибо, очень признателен, мне нравится идея карты.
Если нет ничего общего, наследование тоже не поможет. Обычный трюк для этого — использовать интерфейс маркера, содержащий неэкспортированный метод, и его пустую реализацию по умолчанию. Любая структура, которая может быть возвращена из этой фабрики, встраивает структуру, таким образом реализуя этот интерфейс маркера.