Как ограничить интерфейс {} для определенных типов

Я использую 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, конечно, не поддерживает. Какая была бы альтернатива?

Если нет ничего общего, наследование тоже не поможет. Обычный трюк для этого — использовать интерфейс маркера, содержащий неэкспортированный метод, и его пустую реализацию по умолчанию. Любая структура, которая может быть возвращена из этой фабрики, встраивает структуру, таким образом реализуя этот интерфейс маркера.

Burak Serdar 12.04.2023 22:52

Это хорошая идея, маркерный интерфейс. Я попробую это. Спасибо!

Daniel Stephens 12.04.2023 22:59

Я не понимаю, что именно вы спрашиваете. Если Truck и Car не имеют ничего общего, то как interface{} может быть слишком широким типом? И как "наследование" (вы, наверное, имеете в виду особый способ сделать это в другом языке) может решить это, если у них нет ничего общего?

Erwin Bolwidt 13.04.2023 04:48
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
3
92
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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
}

Вы можете увидеть полный пример здесь.

Это то, что я наконец использовал, большое спасибо!

Daniel Stephens 15.04.2023 03:59

у меня странный пример

Этот пример вернет 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)
}

Большое спасибо, очень признателен, мне нравится идея карты.

Daniel Stephens 15.04.2023 03:59

Другие вопросы по теме