Interfaz vacía de Golang y aserción de tipo

interfaz vacía

definición

La interfaz vacía es una forma especial del tipo de interfaz. Las interfaces ordinarias tienen métodos, pero las interfaces vacías no definen ningún puerto de método. Por lo tanto, podemos decir que todos los tipos implementan al menos interfaces vacías.

type test interface {
}
复制代码

Cada interfaz contiene dos propiedades, una es el valor y otra es el tipo.

var i interface{}
fmt.Printf("类型:%T----值:%v\n", i, i) //类型:<nil>----值:<nil>
复制代码

Se puede ver que para las interfaces vacías, ambas son nulas

Escenas a utilizar

Primero , generalmente declaramos una instancia directamente usando interface{}como tipo, y esta instancia puede contener valores de cualquier tipo.

func main() {
	var i interface{}

	i = 100
	fmt.Println(i) //100

	i = "yif"
	fmt.Println(i) //yif

	i = 3.14
	fmt.Println(i) //3.14

	i = false
	fmt.Println(i) //false
}
复制代码

En segundo lugar , si desea que su función acepte cualquier tipo de valor, también puede usar una interfaz vacía. El siguiente código se imprime normalmente:

func main() {
	i := 100
	s := "yif"
	f := 3.14

	test(i)
	test(s)
	test(f)
}

func test(i interface{}) {
	fmt.Println(i)
}
复制代码

La forma de escribir anterior es un poco engorrosa, puede usar funciones variádicas. como sigue:

func main() {
	i := 100
	s := "yif"
	f := 3.14

	test(i, s, f)
}

func test(res ...interface{}) {
	fmt.Println(res) //res是切片
	for k, v := range res {
		fmt.Println(k, v)
	}
}
复制代码

resultado:

D:\workspace\go\src\test>go run main.go
[100 yif 3.14]
0 100
1 yif
2 3.14 
复制代码

Tercero , también define una matriz, sector, mapa, cadena que puede recibir cualquier tipo, por ejemplo, defina un sector aquí

func main() {
	sli := make([]interface{}, 4)
	sli[0] = 100
	sli[1] = "yif"
	sli[2] = []int{1, 2, 3}
	sli[3] = [...]int{5, 6, 7}
	fmt.Println(sli)
	for k, v := range sli {
		fmt.Println(k, v)
	}
}
复制代码

resultado:

D:\workspace\go\src\test>go run main.go
[100 yif [1 2 3] [5 6 7]]
0 100
1 yif
2 [1 2 3]
3 [5 6 7] 
复制代码

Varios pozos a los que prestar atención en la interfaz vacía.

**Primero,** una interfaz vacía puede tener cualquier valor, pero eso no significa que cualquier tipo pueda aceptar el valor del tipo de interfaz vacía.

Un tipo de interfaz vacío puede contener cualquier valor y también puede recuperar el valor original de la interfaz vacía.

Pero si asigna un objeto de tipo de interfaz vacío a un objeto de tipo fijo (como int, cadena, etc.), se informará un error.

var i interface{} = 100
var t int = i // cannot use i (type interface {}) as type int in assignment: need type assertion
复制代码

Pero puedes usar declaraciones de variables cortas:

var i interface{} = 100
t := i
fmt.Println(t) //100
复制代码

Porque el compilador deducirá el tipo de la variable según el valor del lado derecho del signo igual para completar la inicialización.

**Segundo:** Cuando la interfaz vacía contiene matrices y sectores, el objeto ya no se puede dividir

sli := []int{1, 2, 3, 4}
var i interface{}
i = sli
fmt.Println(i[1:2]) //cannot slice i (type interface {})
复制代码

tipo aserción

La aserción de tipo es una operación que se utiliza en los valores de interfaz para verificar si el valor que tiene una variable de tipo de interfaz implementa la interfaz esperada o el tipo concreto.

Aserción de tipo, solo se pueden afirmar los objetos cuyo tipo estático es una interfaz vacía (interfaz{}); de lo contrario, se generará un error

Dos sintaxis para la aserción de tipo en Go

La primera sintaxis para aserciones de tipo en Go es la siguiente:

t := i.(T)
复制代码

Esta expresión puede afirmar que un objeto de interfaz (i) no es nulo, y el tipo de valor almacenado en el objeto de interfaz (i) es T. Si la afirmación tiene éxito, devolverá el valor a t, y si la afirmación falla , se activará el pánico.

func main() {
	var i interface{} = 100
	t := i.(int)
	fmt.Println(t) //100
	
	fmt.Println("------------------------------------")

	s := i.(string)
	fmt.Println(s)
}
复制代码

Resultado [Error al ejecutar la segunda aserción y pánico activado]:

D:\workspace\go\src\test>go run main.go
100
------------------------------------
panic: interface conversion: interface {} is int, not string

goroutine 1 [running]:
main.main()
        D:/workspace/go/src/test/main.go:32 +0x10e
exit status 2 
复制代码

如果要断言的接口值是 nil,那我们来看看也是不是也如预期一样会触发panic

var i interface{}
var _ = i.(interface{})
复制代码

结果:

D:\workspace\go\src\test>go run main.go
panic: interface conversion: interface is nil, not interface {}

goroutine 1 [running]:
main.main()
        D:/workspace/go/src/test/main.go:27 +0x34
exit status 2 
复制代码

在Go语言中类型断言的另一种语法格式如下:

t, ok:= i.(T)
复制代码

和上面一样,这个表达式也是可以断言一个接口对象(i)里不是 nil,并且接口对象(i)存储的值的类型是 T,如果断言成功,就会返回其类型给 t,并且此时 ok 的值 为 true,表示断言成功。

如果接口值的类型,并不是我们所断言的 T,就会断言失败,但和第一种表达式不同的事,这个不会触发 panic,而是将 ok 的值设为 false ,表示断言失败,此时t 为 T 的零值。

func main() {
    var i interface{} = 10
    t1, ok := i.(int)
    fmt.Printf("%d-%t\n", t1, ok)

    fmt.Println("=====分隔线1=====")

    t2, ok := i.(string)
    fmt.Printf("%s-%t\n", t2, ok)

    fmt.Println("=====分隔线2=====")

    var k interface{} // nil
    t3, ok := k.(interface{})
    fmt.Println(t3, "-", ok)

    fmt.Println("=====分隔线3=====")
    k = 10
    t4, ok := k.(interface{})
    fmt.Printf("%d-%t\n", t4, ok)

    t5, ok := k.(int)
    fmt.Printf("%d-%t\n", t5, ok)
}
复制代码

结果【运行后输出如下,可以发现在执行第二次断言的时候,虽然失败了,但并没有触发了 panic】:

D:\workspace\go\src\test>go run main.go
10-true
=====分隔线1=====
-false
=====分隔线2=====
<nil> - false
=====分隔线3=====
10-true
10-true 
复制代码

上面这段输出,你要注意的是第二个断言的输出在-false 之前并不是有没有输出任何 t2 的值,而是由于断言失败,所以 t2 得到的是 string 的零值也是 "" ,它是零长度的,所以你看不到其输出。

类型断言配合 switch 使用

如果需要区分多种类型,可以使用 type switch 断言。

func main() {
	test(100)
	test("yif")
	test(3.14)
	
	var i interface{} //nil
	test(i)
	
	test(nil)
}

func test(i interface{}) {
	switch r := i.(type) {
	case int:
		fmt.Println(r, "是int型")
	case string:
		fmt.Println(r, "是字符串")
	case nil:
		fmt.Println(r, "是nil")
	default:
		fmt.Println("没有结果!")
	}
}
复制代码

结果:

D:\workspace\go\src\test>go run main.go
100 是int型
yif 是字符串
没有结果!
<nil> 是nil
<nil> 是nil
复制代码

Supongo que te gusta

Origin juejin.im/post/7078550092419956749
Recomendado
Clasificación