Как вы используете полиморфизм с картами Go?

Мне интересно, какие шаблоны следует использовать в Go в таких случаях. Итак, давайте предположим, что у вас есть структура Request, содержащая некоторую информацию для выполнения HTTP-запроса, а также параметры, которые могут быть отправлены в полезных данных, и их соответствующие проверки. Теперь в зависимости от типа данных параметра будут применяться разные типы проверок, поэтому я решил использовать map[string]Validations, где я мог бы хранить тип проверок, упомянутый в объединении Validations (по сути, имея возможность вместить как IntValidations, так и StrValidations на той же карте).

Но приведенный ниже код приведет к ошибке, поскольку Validations можно использовать только как параметр типа, так как же нам добиться этого в Go? В Java этого можно было бы легко достичь с помощью полиморфизма, где Validation был бы родительским классом, а проверки int и float были бы дочерними классами, поэтому позже мы могли бы легко создать экземпляр HashMap из Validations.

Примечание. Я бы хотел избежать использования map[string]interface{}.

type Validations interface {
IntValidations | StrValidations
}

type IntValidations struct {
  MaxVal int
  MinVal int
}

type StrValidations struct {
  MinLength int
  MaxLength int
  Regex string 
}

type Request struct {
 Path string 
 Payload map[string]Validations // Error: Validations cannot be used outside of a type constraint.
}

Используйтеmap[string]Validation, где Validation — это интерфейс с методами, подходящими для проверки. Пример type Validation interface { Do(<insert args here>) error }

Cerise Limón 23.06.2024 21:36

Понятно, но как я смогу использовать это и заполнить структуры IntValidations и StrValidations этим... Не могли бы вы рассказать об этом немного подробнее? Вы предлагаете избавиться от этих двух структур и вместо этого выполнять проверки в методе Do?

ansme 23.06.2024 22:12

Реализуйте методы Do для типов IntValidation и StrValidations. См. Обзор Go для получения информации о том, как реализовать метод и как методы связаны с интерфейсами.

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

Ответы 1

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

Как отметил @Cerise Limón в комментариях, вы можете сделать это вот так.

package main

type Validators interface {
    Validate(value any) error // Can return bool also
}

type IntValidator struct {
    MaxVal int
    MinVal int
}

func (intValidator *IntValidator) Validate(value any) error {
    // run validations
    return nil
}

type StrValidator struct {
    MinLength int
    MaxLength int
    Regex     string
}

func (strValidator *StrValidator) Validate(value any) error {
    // run validations
    return nil
}

type Request struct {
    Path    string
    Payload map[string]Validations
}

Теперь вы можете добавлять валидаторы с помощью

func main() {
    request := Request{Payload: make(map[string]Validations)}
    request.Payload["myIntVar"] = &IntValidations{MinVal: 10, MaxVal: 20}
    request.Payload["myStrVar"] = &IntValidations{MinLen: 10, MaxLen: 15, Regex: "[a-z]+"}

    if err := request.Payload["myIntVar"].Validate(13); err != nil {
        panic("could not validate")
    }
}

Отлично, это именно то, что я искал. Но еще один уточняющий вопрос. Что, если бы у меня был случай, когда хотелось бы создать аналогичную карту, содержащую несколько похожих типов, но в отличие от этого конкретного варианта использования использование такого метода, как Validate, вообще не требуется. Как бы мы тогда достигли того же?

ansme 24.06.2024 03:57

@ansme Опишите, что делает типы «похожими».

Cerise Limón 24.06.2024 04:13

@CeriseLimón Скажем так, это карта map[string]Animal, где мы могли бы хранить подобные типы в качестве значений, например type Cat struct, type Dog struct, где эти структуры просто содержат базовые поля, такие как name string, neutered bool и т. д.. но давайте предположим, что они не требуют любая функциональность... следовательно, базовый интерфейс Animal не имеет определенных для него методов. Тогда как мы сможем создать map[string]Animal?

ansme 24.06.2024 04:28

@ansme Следуйте шаблону в этом ответе, но используйте пустой метод Validate.

Cerise Limón 24.06.2024 04:46

@asme, вы можете создать простой метод Validate с 0 аргументами, ничего не возвращать и реализовать его с пустым телом, чтобы указать, что он реализует интерфейс Validator, но ничего не делает.

Timsib Adnap 24.06.2024 04:59

@TimsibAdnap Вместо использования any Есть ли способ реализовать метод validate с аргументами int, string, специфичными для соответствующих структур реализации?

ansme 25.06.2024 21:27

Да, вы можете использовать универсальный интерфейс. Но общие интерфейсы нельзя хранить на карте. Проверьте это. Я бы порекомендовал вам оставить его как any, а внутри функции Validate отметьте его как if intVal, ok := value.(int); !ok { return err }

Timsib Adnap 26.06.2024 10:40

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