如何检查切片界面元素是否具有相同的动态类型?
How to check if slice interface elements have the same dynamic type?
我有以下结构,它们遵循这个结构:
A
是接口,B
、C
、D
都是接口A
.
的类型
我有一片变量args
,所有类型都带有接口A
,每个都可以是B
、C
、D
类型具体来说。
我想写一个for循环来判断切片中的所有变量是否属于同一动态类型。
我写了下面的代码:
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!")
}
}
}
如何修改代码来实现我想要的?
您不能对接口值使用相等运算符 ==
。即使动态类型相同,如果它们具有不同值的字段,比较也可能 return false。或者,如果 B
、C
和 D
与开始时不可比,它会出现恐慌。
相反,您可以使用反射并在 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
,此函数会报告错误。显然,指针类型与基类型不同。
以下是使用反射包的方法。如果某个元素的类型与第一个元素的类型不同,则切片包含混合值类型。
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
}
下面是不反射的方法。保留一个状态变量,记录最后看到的类型。如果当前类型不是最后一个类型,则切片包含混合值类型。
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
}
我有以下结构,它们遵循这个结构:
A
是接口,B
、C
、D
都是接口A
.
我有一片变量args
,所有类型都带有接口A
,每个都可以是B
、C
、D
类型具体来说。
我想写一个for循环来判断切片中的所有变量是否属于同一动态类型。
我写了下面的代码:
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!")
}
}
}
如何修改代码来实现我想要的?
您不能对接口值使用相等运算符 ==
。即使动态类型相同,如果它们具有不同值的字段,比较也可能 return false。或者,如果 B
、C
和 D
与开始时不可比,它会出现恐慌。
相反,您可以使用反射并在 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
,此函数会报告错误。显然,指针类型与基类型不同。
以下是使用反射包的方法。如果某个元素的类型与第一个元素的类型不同,则切片包含混合值类型。
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
}
下面是不反射的方法。保留一个状态变量,记录最后看到的类型。如果当前类型不是最后一个类型,则切片包含混合值类型。
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
}