Go语言断言和类型查询的实现

 更新时间:2024年01月30日 10:45:35   作者:242030  
Go语言变量类型包含基础类型和复合类型,类型断言一般是对基础类型的处理,本文主要介绍了Go语言断言和类型查询的实现,感兴趣的可以了解一下

1、类型断言

类型断言(Type Assertion)是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型。

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

// i.(TypeNname)
value, ok := x.(T)

其中,x 表示一个接口的类型,如果是具体类型变量,则编译器会报non-interface type xxx on left,T 表示一个具体的类型(也可为接口类型)。

该断言表达式会返回 x 的值(也就是 value)和一个布尔值(也就是 ok),可根据该布尔值判断 x 是否为 T 类型:

  • 如果 T 是具体某个类型,类型断言会检查 x 的动态类型是否等于具体类型 T。如果检查成功,类型断言返回的结果是 x 的动态值,其类型是 T。

  • 如果 T 是接口类型,类型断言会检查 x 的动态类型是否满足 T。如果检查成功,x 的动态值不会被提取,返回值是一个类型为 T 的接口值。

  • 无论 T 是什么类型,如果 x 是 nil 接口值,类型断言都会失败。

示例代码如下:

package main

import (
	"fmt"
)

func main() {
	var x interface{}
	x = 10
	value, ok := x.(int)
	// 10,true
	fmt.Print(value, ",", ok)
}

运行结果如下:

# 程序结果
10,true

需要注意如果不接收第二个参数也就是上面代码中的 ok,断言失败时会直接造成一个 panic,如果 x 为 nil 同样也会 panic。

示例代码如下:

package main

import (
	"fmt"
)

func main() {
	var x interface{}
	x = "Hello"
	value := x.(int)
	fmt.Println(value)
}

运行结果如下:

# 输出结果
panic: interface conversion: interface {} is string, not int

接口断言通常可以使用 comma,ok 语句来确定接口是否绑定某个实例类型,或者判断接口绑定的实例类型是否实现另一个接口。

re,ok := body.(io.ReadCloser)
if,ok :=  r.Body.(*maxBytesReader);

2、类型查询

接口类型查询的语法格式如下:

switch v := i.(type){
	case typel:
		XXXX
	case type2:
		XXXX
	default:
		XXXX
}

接口查询有两层语义,一是查询一个接口变量底层绑定的底层变量的具体类型是什么,二是查询接口变量绑定的底

层变量是否还实现了其他接口。

(1)、i 必须是接口类型

具体类型实例的类型是静态的,在类型声明后就不再变化,所以具体类型的变量不存在类型查询,类型查询一定是

对一个接口变量进行操作。也就是说,上文中的i必须是接口变量,如果i是未初始化接口变量,则v的值是 nil。

package main

import (
	"fmt"
	"io"
)

func main() {
	var i io.Reader
	//此处i是为未初始化的接口变量,所以v为nil
	switch v := i.(type) {
	case nil:
		//<nil>
		fmt.Printf("%T\n", v)
	default:
		fmt.Printf("default")
	}
}

(2)、case 字句后面可以跟非接口类型名,也可以跟接口类型名,匹配是按照 case 子句的顺序进行的。

  • 如果 case 后面是一个接口类型名,且接口变量i绑定的实例类型实现了该接口类型的方法,则匹配成,v的类型是接口类型,v底层绑定的实例是i绑定具体类型实例的副本。

  • 如果 case 后面是一个具体类型名,且接口变量i绑定的实例类型和该具体类型相同,则匹配成功,此时v 就是该具体类型变量,v的值是i绑定的实例值的副本。

  • 如果 case 后面跟着多个类型,使用逗号分隔,接口变量i绑定的实例类型只要和其中一个类型匹配,则直接使用o赋值给v,相当于 v:=o。这个语法有点奇怪,按理说编译器不应该允许这种操作,语言实现者可能想让type switch 语句和普通的 switch 语句保持一样的语法规则,允许发生这种情况。

  • 如果所有的case字句都不满足,则执行 default 语句,此时执行的仍然是 v:=o,最终v的值是o。此时使用v没有任何意义。

  • fallthrough 语句不能在 Type Switch 语句中使用。

package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	var i io.Reader
	// 此处i是为未初始化的接口变量,所以v为nil
	switch v := i.(type) {
	case nil:
		// <nil>
		fmt.Printf("%T\n", v)
	default:
		fmt.Printf("default")
	}
	f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	i = f
	switch v := i.(type) {
	// i的绑定的实例是*osFile类型,实现了io.ReadWriter接口,所以下面case匹配成功
	case io.ReadWriter:
		// v是io.ReadWriter接口类型,所以可以调用Write方法
		v.Write([]byte("io.ReadWriter\n"))
		// Type Switch Result: io.ReadWriter
		fmt.Println("Type Switch Result: io.ReadWriter")
	// 由于上一个case已经匹配,就算这个case也匹配,也不会走到这里
	case *os.File:
		v.Write([]byte("*os.File\n"))
		fmt.Println("Type Switch Result: *os.File")
		//这里可以调用具体类型方法
		v.Sync()
	default:
		fmt.Println("Type Switch Result: unknown")
		return
	}

	switch v := i.(type) {
	// 匹配成功,v的类型就是具体类型*os.File
	case *os.File:
		v.Write([]byte("*os.File\n"))
		// Type Switch Result: *os.File
		fmt.Println("Type Switch Result: *os.File")
		v.Sync()
	//由于上一个case已经匹配,就算这个case也匹配,也不会走到这里
	case io.ReadWriter:
		//v是io.ReadWriter接口类型,所以可以调用Write方法
		v.Write([]byte("io.ReadWriter\n"))
		fmt.Println("Type Switch Result: io.ReadWriter")
	default:
		fmt.Println("Type Switch Result: unknown")
		return
	}

	switch v := i.(type) {
	//多个类型,f满足其中任何一个就算匹配
	case *os.File, io.ReadWriter:
		// 此时相当于执行力v := i ,v和i是等价的,使用v没有意义。
		if v == i {
			// true
			fmt.Println(true)
		}
	default:
		return
	}
}

# 程序输出
<nil>
Type Switch Result: io.ReadWriter
Type Switch Result: *os.File
true 

package main

import (
	"fmt"
)

func main() {
	var a int
	a = 10
	// the type of a is int
	getType(a)
}

func getType(a interface{}) {
	switch a.(type) {
	case int:
		fmt.Println("the type of a is int")
	case string:
		fmt.Println("the type of a is string")
	case float64:
		fmt.Println("the type of a is float")
	default:
		fmt.Println("unknown type")
	}
}

# 程序输出
the type of a is int

 到此这篇关于Go语言断言和类型查询的实现的文章就介绍到这了,更多相关Go语言断言和类型查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • Go语言安装和GoLand2021最全超详细安装教程

    Go语言安装和GoLand2021最全超详细安装教程

    Go语言和GoLand的关系好比于java和idea、python和pycharm,因此我们需要先安装好Go语言后才能安装GoLand。它的安装和java,python的安装大同小异,好了,下面给大家带来了GoLand2021安装教程,需要的朋友参考下吧
    2021-08-08
  • Go高级特性探究之优先级队列详解

    Go高级特性探究之优先级队列详解

    Heap 是一种数据结构,这种数据结构常用于实现优先队列,这篇文章主要就是来和大家深入探讨一下GO语言中的优先级队列,感兴趣的可以了解一下
    2023-06-06
  • Go 语言中静态类型和动态类型的使用

    Go 语言中静态类型和动态类型的使用

    本文主要介绍了Go语言中的静态类型和动态类型,静态类型在编译时确定,提供了类型安全,性能优化和代码清晰,而动态类型在运行时确定,提供了更高的灵活性,但可能引发运行时错误,下面就来介绍一下,感兴趣的可以了解一下
    2024-10-10
  • Go  iota 常量基本语法介绍

    Go  iota 常量基本语法介绍

    这篇文章主要介绍了Go 为什么要设计 iota 常量,我们介绍了 Go 中 iota 的基本语法。同时基于历史资料针对 iota 到底是什么,为什么要这么叫,又有什么用进行了一番研究,需要的朋友可以参考下
    2022-06-06
  • Golang中HTTP路由设计的使用与实现

    Golang中HTTP路由设计的使用与实现

    这篇文章主要介绍了Golang中HTTP路由设计的使用与实现,为什么要设计路由规则,因为路由规则是HTTP的请求按照一定的规则 ,匹配查找到对应的控制器并传递执行的逻辑,需要的朋友可以参考下
    2023-05-05
  • go语言base64加密解密的方法

    go语言base64加密解密的方法

    这篇文章主要介绍了go语言base64加密解密的方法,实例分析了Go语言base64加密解密的技巧,需要的朋友可以参考下
    2015-03-03
  • Go 切片导致内存泄露的几种原因

    Go 切片导致内存泄露的几种原因

    某些情况下,对一个已存在的切片或数组进行切分操作可能会导致内存泄漏,本文主要介绍了Go 切片导致内存泄露的几种原因,感兴趣的可以了解一下
    2023-05-05
  • Go语言开发前后端不分离项目详解

    Go语言开发前后端不分离项目详解

    这篇文章主要为大家介绍了Go语言开发前后端不分离项目详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • golang Gorm框架讲解

    golang Gorm框架讲解

    gorm是一个使用Go语言编写的ORM框架,这篇文章主要介绍了golang Gorm框架,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • golang 生成定单号的操作

    golang 生成定单号的操作

    这篇文章主要介绍了golang 生成定单号的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12

最新评论