Как вернуть общий тип в go

Я новичок, все еще нахожусь на этапе обучения и не смог найти ответов, соответствующих моей проблеме, поэтому, пожалуйста, не ставьте минус. У меня есть общий интерфейс, экземпляр которого можно создать с помощью двух параметров типа, и у меня нет абсолютно никаких проблем с созданием новых карт с типами, реализующими этот интерфейс. Я также могу вставлять и индексировать ключи, но столкнулся с проблемой при попытке вернуть значения с карт с помощью общей функции. Пожалуйста, помогите мне исправить функцию GetGenericIfaceVal, упомянутую ниже. Компилятор жалуется, что не может вернуть тип c, поскольку это IncompatibleAssign.

package main

import (
  "strings"
)

type GenericIface[rType ~map[string]T, T interface{}] interface {
  GetSubTypes() rType
}

type t1 struct  {
  subTypes r1
}

type r1 map[string]r1

type t2 struct {
  subTypes r2
}

type r2 map[string]t2


var mapFirst = make(map[string]GenericIface[r1, r1])
var mapSecond = make(map[string]GenericIface[r2, t2])

//cannot use mapFirst[cType] (map index expression of type GenericIface[r1, r1]) as c value in return statement compiler (IncompatibleAssign) [29, 12]
func GetGenericIfaceVal[c GenericIface[M, T],M ~map[string]T, T interface{}](cType string) c {
  if strings.HasPrefix(cType, "$") {
    return mapFirst[cType]
  }
  return mapSecond[cType]
}

func (t *t1) GetSubTypes() r1 {
  return t.subTypes
}

func (t *t2) GetSubTypes() r2 {
  return t.subTypes
}

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

Ответы 1

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

При работе с дженериками, особенно в go, все становится сложнее. Нам нужно осторожно обращаться со сложными ограничениями типов. В вашем случае проблема, похоже, связана с ограничениями типов и возвращаемыми значениями функции. Вот как вы можете справиться с этим:

package main

import (
    "fmt"
    "strings"
)


type GenericIface[M ~map[string]T, T any] interface {
    GetSubTypes() M
}


type t1 struct {
    subTypes r1
}

type r1 map[string]r1

type t2 struct {
    subTypes r2
}

type r2 map[string]t2


var mapFirst = make(map[string]GenericIface[r1, r1])
var mapSecond = make(map[string]GenericIface[r2, t2])

GenericIface[r2, t2] based on the input type.
func GetGenericIfaceVal[M ~map[string]T, T any](cType string) GenericIface[M, T] {
    if strings.HasPrefix(cType, "$") {
        return mapFirst[cType].(GenericIface[M, T])
    }
    return mapSecond[cType].(GenericIface[M, T])
}

interface.
func (t *t1) GetSubTypes() r1 {
    return t.subTypes
}

func (t *t2) GetSubTypes() r2 {
    return t.subTypes
}

func main() {

    mapFirst["$example"] = &t1{subTypes: make(r1)}
    mapSecond["example"] = &t2{subTypes: make(r2)}


    val1 := GetGenericIfaceVal[r1, r1]("$example")
    fmt.Printf("val1: %T\n", val1)


    val2 := GetGenericIfaceVal[r2, t2]("example")
    fmt.Printf("val2: %T\n", val2)
}

Причина:

Вам не хватало утверждения типа. Это связано с тем, как Go обрабатывает параметры типов и интерфейсы, особенно с дженериками.

  • Когда вы определяете интерфейс (вместе с дженериками) как GenericIface[M, T], вы говорите, что методы интерфейса будут работать с типами (определяемыми во время компиляции). Но на самом деле структуры данных (например, MapFirst и MapSecond) представляют собой просто карты с общими интерфейсами.
  • Когда вы получаете элемент, компилятор Go знает только, что он имеет тип GenericIface[_, _]. Недостаточно информации, чтобы сделать вывод, что он соответствует конкретному GenericIface[M, T], который вы хотите вернуть. Таким образом, невозможно гарантировать, что возвращаемый элемент имеет точный тип GenericIface[M, T] во время выполнения.
  • Утверждая тип, вы, как программист, гарантируете компилятору, что определенное значение соответствует определенному типу.

Вы можете узнать больше об этом здесь:

https://www.freecodecamp.org/news/generics-in-golang/

https://callistaenterprise.se/blogg/teknik/2022/05/30/go-generics-in-functional-style/

https://programmingpercy.tech/blog/learning-generics-in-go/

https://thewikihow.com/video_Eor1w37tVNw

Понятно, поэтому нам нужно было ввести утверждения. Не могли бы вы немного рассказать, почему без утверждений это не работает?

ansme 14.07.2024 10:33

Спасибо! Я проголосовал за это. И последний вопрос: не могли бы вы поделиться ссылкой, где я мог бы подробно прочитать об этом? Тогда я обязательно отмечу это как правильный ответ.

ansme 14.07.2024 11:33

Я добавил статьи и видео, где вы можете подробно узнать об этом.

abuzain 14.07.2024 11:43

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