Как проверить три разных ключа структуры на карте golang?

У меня есть метод ниже, в котором я создаю три разных объекта структуры для проверки в качестве ключа на моей карте name. Если я могу найти значение, я возвращаюсь обратно, иначе я возвращаю пустую строку и статус.

func (r *clientRepo) GetName(id int64, name map[models.LocaleInfo]string, clientId int32, code models.Locale) (string, bool) {
    localeInfo := models.LocaleInfo{
        Locale:  code,
        GroupID: int(clientId),
    }

    localeInfoUS := models.LocaleInfo{
        Locale:  "US",
        GroupID: int(clientId),
    }

    localeInfoGB := models.LocaleInfo{
        Locale:  "GB",
        GroupID: int(clientId),
    }

    value := ""
    ok := false
    if value, ok = name[localeInfo]; !ok {
        if value, ok = name[localeInfoUS]; !ok {
            if value, ok := name[localeInfoGB]; !ok {
                errs.Newf("Unable to find locale for ProductId: %d", id)
                return value, ok
            }
        }
    }
    
    return value, ok
}

Есть ли способ улучшить приведенный выше код, где мне не нужно хранить отдельную строку для каждой информации о локали США и ГБ. Мой блок if тоже выглядит очень вложенным, и я думаю, что его тоже можно значительно улучшить.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Специальную форму «запятая-ок» можно использовать только в задании, поэтому сделать ее более компактной нельзя.

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

Используя дженерики Go 1.18, вы можете заставить его работать с любым типом карты:

func findKeys[K comparable, V any](m map[K]V, keys ...K) (v V, ok bool) {
    for _, key := range keys {
        if v, ok = m[key]; ok {
            return
        }
    }
    return
}

Тестирование:

m := map[int]string{
    1: "one",
    2: "two",
    3: "three",
    4: "four",
}

fmt.Println(findKeys(m, 5, 6, 4))
fmt.Println(findKeys(m, 1, 2, 6))
fmt.Println(findKeys(m, 6, 8))

Какие выходы (попробуйте на Игровая площадка):

four true
one true
 false

Примечание: если вы используете Go до версии Go 1.18, просто используйте неуниверсальную версию findKeys():

func findKeys(m map[models.LocaleInfo]string, keys ...models.LocaleInfo) (v string, ok bool) {
    for _, key := range keys {
        if v, ok = m[key]; ok {
            return
        }
    }
    return
}

Вы можете использовать это findKeys() следующим образом:

value, ok := findKeys(name, localeInfo, localeInfoUS, localeInfoGB)
if !ok {
    errs.Newf("Unable to find locale for ProductId: %d", id)
}
return value, ok

Также обратите внимание, что если вы используете неуниверсальную версию, поскольку она в любом случае будет ограничена вашим типом карты, вы можете переместить в нее больше кода: она может обрабатывать создание ключа, поэтому вам нужно передать только значения локали string. (и clientId):

func findKeys(names map[models.LocaleInfo]string, clientId int, locales ...string) (v string, ok bool) {
    key := models.LocaleInfo{GroupID: clientId}
    for _, locale := range locales {
        key.Locale = locale
        if v, ok = names[key]; ok {
            return
        }
    }
    return
}

Вызов это выглядит так:

value, ok := findKeys(names, int(clientId), code, "US", "GB")

См. соответствующий вопрос: Проверьте, существует ли ключ на нескольких картах в одном условии

Спасибо за ваше предложение. Я все еще работаю с 1.17. Как мне добиться этого лучше, используя 1.17? В моем случае карта такая же, но разные ключи.

rosed 18.03.2022 08:29

@rosed Тогда просто используйте неуниверсальную версию findKeys(), см. отредактированный ответ.

icza 18.03.2022 08:31

Понятно. Это имеет смысл. Так что у меня по-прежнему будет три разных объекта localeInfo, так как это просто блок, если он улучшен. Верно?

rosed 18.03.2022 08:33

@rosed У вас может быть столько ключей, сколько вы хотите. Также обратите внимание, что если вы используете неуниверсальную версию, которая в любом случае ограничена вашим типом карты, вы можете переместить создание ключа в служебную функцию, поэтому ее использование будет намного проще. Смотрите отредактированный ответ.

icza 18.03.2022 08:54

Быстрый вопрос - range locale { это должно быть locales верно? А также получение ошибки в key.Locale = locale bcoz key.Locale — это объект.

rosed 18.03.2022 18:41

@rosed Да, locale => locales была опечатка, но обратите внимание, что в этой версии locales — это string срез, а не срез объекта! Итак, key.Locale = locale действителен.

icza 18.03.2022 19:19

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