英文:
How to check if slice interface elements have the same dynamic type?
问题
我有以下的结构体,它们遵循这个结构:
A
是接口,B
、C
、D
都是类型,且实现了接口 A
。
我有一个变量切片 args
,其中的每个变量都是类型为接口 A
的类型,具体可以是 B
、C
、D
中的一种。
我想写一个循环来判断切片中的所有变量是否都属于同一动态类型。
我写了以下代码:
var existingTyp A
for i, d := range args {
switch typ := d.(type) {
case *B, *C, *D:
if existingTyp == nil {
existingTyp = typ
} else {
if typ != existingTyp {
panic("error!")
}
}
}
如何修改代码以实现我想要的效果?
英文:
I have the following structs and they follow this structure:
A
is the interface, and B
, C
, D
are all types with interface A
.
I have a slice of variables args
all with type with interface A
, each of which can be B
, C
, D
type specifically.
I'd like to write a for loop to judge if all variables in the slice fall into the same dynamic type.
I wrote the following code:
var existingTyp A
for i, d := range args {
switch typ := d.(type) {
case *B, *C, *D:
if existingTyp == nil {
existingTyp = typ
} else {
if typ != existingTyp {
panic("error!")
}
}
}
How to revise the code to achieve what I want?
答案1
得分: 3
你不能在接口值上使用等号运算符==
。即使动态类型相同,如果它们具有不同值的字段,比较可能返回false。或者如果B
、C
和D
本身不可比较,则会引发panic。
相反,你可以使用反射,在reflect.Type
上使用==
。这种解决方案不需要在添加更多实现A
的类型时更新代码。
func dynamicTypesEq(args []A) bool {
var a reflect.Type
for _, d := range args {
t := reflect.TypeOf(d)
if a == nil {
a = t
continue
}
if a != t {
return false
}
}
return true
}
使用一些示例切片调用该函数:
func main() {
a := []A{&B{}, &B{}, &B{}}
fmt.Println(dynamicTypesEq(a)) // true
b := []A{&C{}, &B{}, &B{}}
fmt.Println(dynamicTypesEq(b)) // false
c := []A{&D{}, &D{}, &B{}}
fmt.Println(dynamicTypesEq(c)) // false
}
请注意,如果输入中同时包含*B
和B
,该函数将返回false。显然,指针类型与基本类型不同。
Playground链接:https://go.dev/play/p/QOCvSyxGPRU
英文:
You can't use the equality operator ==
on the interface values. Even if the dynamic types are the same, the comparison may return false if they have fields with different values. Or it panics if B
, C
and D
aren't comparable to begin with.
Instead you can use reflection and use ==
on reflect.Type
. This solution doesn't require you to update the code if you add more types that implement A
.
func dynamicTypesEq(args []A) bool {
var a reflect.Type
for _, d := range args {
t := reflect.TypeOf(d)
if a == nil {
a = t
continue
}
if a != t {
return false
}
}
return true
}
Calling the function with some example slices:
func main() {
a := []A{&B{}, &B{}, &B{}}
fmt.Println(dynamicTypesEq(a)) // true
b := []A{&C{}, &B{}, &B{}}
fmt.Println(dynamicTypesEq(b)) // false
c := []A{&D{}, &D{}, &B{}}
fmt.Println(dynamicTypesEq(c)) // false
}
Note that this function reports false in case the input has *B
and B
. Clearly, a pointer type is not the same as the base type.
Playground: https://go.dev/play/p/QOCvSyxGPRU
答案2
得分: 2
以下是使用reflect包进行翻译的代码:
// 使用reflect包进行检查
func check(args []interface{}) bool {
if len(args) == 0 {
return true
}
t := reflect.TypeOf(args[0])
for _, v := range args[1:] {
if reflect.TypeOf(v) != t {
return false
}
}
return true
}
以下是不使用reflect进行翻译的代码:
// 不使用reflect进行检查
func check(args []interface{}) bool {
const (
initState = iota
typeB
typeC
typeD
)
state := initState
for _, d := range args {
switch d.(type) {
case *B:
if state != initState && state != typeB {
return false
}
state = typeB
case *C:
if state != initState && state != typeC {
return false
}
state = typeC
case *D:
if state != initState && state != typeD {
return false
}
state = typeD
default:
panic("unsupported type")
}
}
return true
}
希望对你有帮助!
英文:
Here's how to do it using the reflect package. If type of some element is different from the type of the first element, then the slice contains mixed value types.
func check(args []interface{}) bool {
if len(args) == 0 {
return true
}
t := reflect.TypeOf(args[0])
for _, v := range args[1:] {
if reflect.TypeOf(v) != t {
return false
}
}
return true
}
Here's how to do it without reflect. Keep a state variable that records the last type seen. If the current type is not the last type, then the slice contains mixed value types.
func check(args []interface{}) bool {
const (
initState = iota
typeB
typeC
typeD
)
state := initState
for _, d := range args {
switch d.(type) {
case *B:
if state != initState && state != typeB {
return false
}
state = typeB
case *C:
if state != initState && state != typeC {
return false
}
state = typeC
case *D:
if state != initState && state != typeD {
return false
}
state = typeD
default:
panic("unsupported type")
}
}
return true
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论