Go: функция, которая будет использовать карты с различными типами значений - PullRequest
0 голосов
/ 10 февраля 2020

В моем коде мне нужна функция, которая возвращает упорядоченный фрагмент ключей с карты.

m1 := make(map[string]string)
m2 := make(map[string]int)

И теперь мне нужно вызвать функцию, передающую оба типа карт:

keys1 := sortedKeys(m1)
keys2 := sortedKeys(m1)

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

Вопрос: Как использовать одну реализацию для двух карт? Или есть какой-то другой способ решения проблемы элегантным способом?

Моя первая идея состояла в том, чтобы использовать map[string]interface{} в качестве типа аргумента, но вы не можете назначить ни map[string]string, ни map[string]int

Мой код:

func sortedKeys(m map[string]string) []string {
    var keys []string
    for key := range m {
        keys = append(keys, key)
    }
    sort.Strings(keys)
    return keys
}

Мне пришлось бы повторить тот же код, но для map[string]int.

1 Ответ

3 голосов
/ 10 февраля 2020

Вы можете использовать интерфейс {} и использовать отражение для достижения этой цели.

Вы можете написать две функции для одной и той же функции, но она просто не масштабируется, скажем, вы поддерживаете string и int сейчас, но вы будете sh для поддержки int64, float64, bool или struct в будущем. Наличие общей функции с использованием map [string] interface {} и использование отражения - это путь к go.

Рекомендуемый код:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    m1 := make(map[string]string)
    m2 := make(map[string]int)

    m1["a"] = "b"
    m1["b"] = "c"

    m2["a"] = 1
    m2["b"] = 2

    fmt.Println(sortedKeys(m1))
    fmt.Println(sortedKeys(m2))
}

// Returns slice of values in the type which is sent to it
func sortedKeys(m interface{}) interface{} {

    if m == nil {
       return nil
    }

    if reflect.TypeOf(m).Kind() != reflect.Map {
        return nil
    }

    mapIter := reflect.ValueOf(m).MapRange()
    mapVal := reflect.ValueOf(m).Interface()

    typ := reflect.TypeOf(mapVal).Elem()
    outputSlice := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0)


    for mapIter.Next() {
       outputSlice = reflect.Append(outputSlice, mapIter.Value())
    }


    return outputSlice.Interface()


}

Вывод:

[ bc]

[1 2]

https://play.golang.org/p/2fkpydH9idG

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...