【问题标题】:Type assertion of a non-exported type非导出类型的类型断言
【发布时间】:2019-08-31 16:09:13
【问题描述】:

我正在使用 3rd 方包,它允许您通过导出的函数创建某种非导出类型的结构。

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
    }
}

还有其他方法可以达到同样的效果吗?

【问题讨论】:

  • 你试过reflection吗?
  • @mkopriva 还没有。我是这门语言的新手,到目前为止我还没有使用过。

标签: go types


【解决方案1】:

您可以使用反射将值的类型与squirrel.expr 的类型进行比较。这里的type表示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]

注意:

通过传递squirrel.Expr() 调用(类型为squirrel.expr)的返回值,我们获得了要过滤掉的值的reflect.Type 描述符。在这种情况下这很好,但如果仅仅为了获取类型而调用此函数是不可行的(例如,调用具有必须避免的副作用),我们可以避免这种情况。我们可以通过反射获取squirrel.Expr函数本身的reflect.Type描述符,并获取其返回类型的类型描述符。可以这样做:

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

【讨论】:

  • 这个方法仍然需要访问未导出的类型。请注意,OP 需要比较的类型是expr,而不是Expr
  • 使用reflect.TypeOf(v).Name() == "expr" 可以稍微笨拙一点。
  • @Adrian 我的解决方案没有引用未导出的类型,它使用导出的squirrel.Expr()函数的返回值,这是有效的。如果调用它不可行,我们可以使用反射来“提取”Expr() 的返回类型,但在这种情况下并非如此。使用 Type.Name() 的缺点比它提供的易用性要多。
猜你喜欢
  • 2016-10-03
  • 2019-07-28
  • 2018-11-19
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 2021-05-24
  • 2014-01-22
  • 1970-01-01
相关资源
最近更新 更多