Утверждение типа неэкспортируемого типа

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

package squirrel

type expr struct {
    sql string
    args []interface{}
}

func Expr(sql string, args ...interface{}) expr {
    return expr{sql: sql, args: args}
}

Из-за того, как некоторые другие функции этой библиотеки принимают данные, у меня получилась такая карта:

m := map[string]interface{} {
    "col1": 123,
    "col2": "a_string",
    "col3": Expr("now()"),
}

но из-за другой функции в этой библиотеке мне нужно отфильтровать все squirrel.expr с этой карты.

Очевидно, я не смог напрямую установить тип, сделав так:

filtered := make(map[string]interface{})
for k, v := range m {
    switch v.(type) {
    case squirrel.expr:
        continue
    default:
        filtered[k] = v
    }
}

Есть ли другой способ добиться того же результата?

Вы пробовали отражение?

mkopriva 10.04.2019 11:02

@mkopriva Пока нет. Я новичок в этом языке и до сих пор им не пользовался.

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

Ответы 1

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

Вы можете использовать отражение, чтобы сравнить тип значений с типом squirrel.expr. Тип здесь означает дескрипторы reflect.Type, полученные reflect.TypeOf().

Например:

m := map[string]interface{}{
    "col1": 123,
    "col2": "a_string",
    "col3": squirrel.Expr("now()"),
}
fmt.Println(m)

exprType := reflect.TypeOf(squirrel.Expr(""))

filtered := make(map[string]interface{})
for k, v := range m {
    if reflect.TypeOf(v) == exprType {
        continue
    }
    filtered[k] = v
}
fmt.Println(filtered)

Это выведет:

map[col1:123 col2:a_string col3:{now() []}]
map[col1:123 col2:a_string]

Примечание:

Мы получили дескриптор reflect.Type значений, которые мы хотим отфильтровать, передав возвращаемое значение вызова squirrel.Expr() (типа squirrel.expr). В данном случае это нормально, но если невозможно вызвать эту функцию только для получения типа (например, вызов имеет побочные эффекты, которых следует избегать), этого можно избежать. Мы можем использовать отражение, чтобы получить дескриптор reflect.Type самой функции squirrel.Expr и получить дескриптор типа ее возвращаемого типа. Вот как это можно сделать:

exprType := reflect.TypeOf(squirrel.Expr).Out(0)

Этот метод по-прежнему требует доступа к неэкспортированному типу. Обратите внимание, что тип OP, с которым нужно сравнивать, — это expr, а не Expr.

Adrian 10.04.2019 15:23

Это можно было бы сделать немного более неуклюже, используя reflect.TypeOf(v).Name() == "expr".

Adrian 10.04.2019 15:25

@Adrian Мое решение не относится к неэкспортированному типу, оно использует возвращаемое значение экспортированной функции squirrel.Expr(), которое является допустимым. Мы могли бы использовать отражение, чтобы «извлечь» возвращаемый тип Expr(), если его вызов невозможен, но в данном случае это не так. Использование Type.Name() имеет больше недостатков, чем простота, которую оно обеспечивает.

icza 10.04.2019 15:29

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