英文:
Converting private, dynamic type from interface{}
问题
我正在尝试测试一个 SQL 查询,其中一个参数是 gosnowflake.Array
(实质上是一个对切片的包装器),使用 go-sqlmock
包。通常情况下,这样的情况需要我创建一个值转换器,我已经包含了以下代码:
func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) {
casted, ok := v.(*[]T)
if ok {
Expect(*casted).Should(HaveLen(len(opt.Expected)))
for i, c := range *casted {
Expect(c).Should(Equal(opt.Expected[i]))
}
} else {
fmt.Printf("Type: %T\n", v)
return v, nil
}
return "TEST_RESULT", nil
}
现在,这个函数会为提交给查询的每个参数调用。我使用它来测试切片中的值的正确性,或者如果不是切片,则直接传递参数。我遇到的问题是,当我创建一个 arrayConverterOption[string]
并给它一个 gosnowflake.Array(["A", "B", "C"])
作为参数时,类型断言失败,因为 gosnowflake.Array
返回一个内部动态类型 *stringArray
,它被定义为 *[]string
。
所以你可以看到我的困境。一方面,我不能转换 v
,因为它是一个 interface{}
,我也不能给 v
起别名,因为内部类型不是 *[]string
,而是 *stringArray
。那么,在这种情况下我该怎么办呢?
英文:
I'm trying to test around an SQL query wherein one of the arguments is a gosnowflake.Array
(essentially a wrapper to a slice) using the go-sqlmock
package. Normally, something like this requires me to create a value converter, which I have included:
func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) {
casted, ok := v.(*[]T)
if ok {
Expect(*casted).Should(HaveLen(len(opt.Expected)))
for i, c := range *casted {
Expect(c).Should(Equal(opt.Expected[i]))
}
} else {
fmt.Printf("Type: %T\n", v)
return v, nil
}
return "TEST_RESULT", nil
}
Now, this function is called for every argument submitted to the query. I use it to test the correctness of the values in the slice or pass the argument through if it isn't one. The problem I'm having is that, when I create a arrayConverterOption[string]
and give it a gosnowflake.Array(["A", "B", "C"])
as an argument, the type assertion fails because gosnowflake.Array
returns an internal dynamic type, *stringArray
, which is defined as a *[]string
.
So you can see my dilemma here. On the one hand, I can't convert v
because it's an interface{}
and I can't alias v
because the inner type is not *[]string
, but *stringArray
. So then, what should I do here?
答案1
得分: 0
我没有找到不使用反射的方法来实现这个。然而,通过使用反射,我成功地实现了它:
var casted []T
var ok bool
value := reflect.ValueOf(v)
if value.Kind() == reflect.Pointer {
if inner := value.Elem(); inner.Kind() == reflect.Slice {
r := inner.Convert(reflect.TypeOf([]T{})).Interface()
casted, ok = r.([]T)
}
}
所以,这段代码专门检查指向切片的任何内容,这是我的动态类型。然后,它使用反射将内部对象转换为我期望的切片类型。之后,我调用Interface()
方法来从反射值中获取interface{}
,然后将其转换为[]T
类型。这样就成功了。如果失败了,那么我就不是在处理这些动态类型的切片,我可以按照正常的方式处理该类型。
英文:
I didn't find a way to do this without resulting to reflection. However, with reflction I did manage it:
var casted []T
var ok bool
value := reflect.ValueOf(v)
if value.Kind() == reflect.Pointer {
if inner := value.Elem(); inner.Kind() == reflect.Slice {
r := inner.Convert(reflect.TypeOf([]T{})).Interface()
casted, ok = r.([]T)
}
}
So, this code checks specifically for anything that is a pointer to a slice, which my dynamic type is. Then it uses reflection to convert the inner object to the slice type I was expecting. After that, I call Interface()
on the result to get the interface{}
from the reflected value and then cast it to a []T
. This succeeds. If it doesn't then I'm not working with one of those dynamically typed slices and I can handle the type normally.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论