当前位置: 首页 > news >正文

Go基础学习04-变量重声明;类型转换;类型断言;Unicode代码点;类型别名;潜在类型

目录

变量重声明

类型断言

类型转换

 类型转换注意事项

Unicode代码点

类型别名、潜在类型

  类型别名的意义


变量重声明

编写代码:

package mainimport "fmt"var container = []string{"Beijing", "Shanghai"}func main() {fmt.Println(container)container = []string{"Hello", "Hi"}fmt.Printf("variable redeclare %s\n", container)container := map[int]string{1: "Beijing", 2: "Shanghai"}strings, ok := interface{}(container).([]string)if ok {fmt.Println("Container type is []string...")fmt.Println(strings)} else {fmt.Println("Container type is map...")fmt.Printf("strings is %v\n", strings)}fmt.Println(container)
}

        上述代码首先定义一个字符串数组,其名称为container,在main函数中,首先对container进行短变量重赋值,随后又对container使用短变量重新赋值,但这次赋值的对象类型不是[]string而是一个map类型,其key为int,value为string。此时产生的现象在Go中称为可重名变量的类型不同,原先类型为[]string,随后将其类型更改为map[int][string]。上述代码执行结果如下:

        在使用:=对变量进行重声明之后,如果前后对应的变量类型不一致,此时一般需要进行类型断言,来确定具体变量对应的类型如:是[]string还是map[int][string]以确定后面遍历操作。

        下面将补充一下类型转换以及类型断言相关知识: 

类型断言

        在本篇开篇提供的代码中:

         上述方框中的.([]string)就是类型断言:

        类型断言表达式的语法形式是x.(T)。其中的x代表要被判断类型的那个值。这个值当下的类型必须是接口类型的,不过具体是哪个接口类型其实是无所谓的。所以,当这里的container变量类型不是任何的接口类型时,我们就需要先把它转成某个接口类型的值(具体参考下面类型转换知识)。如果container是某个接口类型的,那么这个类型断言表达式就可以是container.([]string)。

        这里使用类型断言将接口类型转换为[]string,同时类型断言等式左边有两个变量,变量ok表示是否能将接口类型变量断言为字符串数组,如果可以断言,则ok值为true同时转换后的字符串数组结果存储到strings变量中;如果不能将接口类型的变量转换为字符串数组,此时ok的值为false,并且strings值为[](nil)参考上面代码运行结果。

类型转换

        类型转换的语法形式是T(x)。
        其中的x可以是一个变量,也可以是一个代表值的字面量(比如1.23和struct{}),还可以是一个表达式。如果是表达式,那么该表达式的结果只能是一个值,而不能是多个值。在这个上下文中,x可以被叫做源值,它的类型就是源类型,而那个T代表的类型就是目标类型。

        如果从源类型到目标类型的转换是不合法的,那么就会引发一个编译错误。

strings, ok := interface{}(container).([]string)

        上面代码中的interface{}(containter)就是类型转换,当container不是一个接口类型时,通过类型转换将其转换为接口类型。在Go语言中,interface{}代表空接口,任何类型都是它的实现类型。任何类型的值都可以很方便地被转换成空接口的值。

        关于上面interface{}中的{}的解释参考下面图片: 

 类型转换注意事项

对于类型转换而言常见的需要遵循的转换规则如下:

  1. 对于整数类型值、整数常量之间的类型转换,原则上只要源值在目标类型的可表示范围内
    就是合法的。
    1. uint8(255)可以把无类型的常量255转换为uint8类型的值,是因为255在 [0,255] 的范围内。但需要特别注意的是,源整数类型的可表示范围较大,而目标类型的可表示范围较小的情况,比如把值的类型从int16转换为int8,此时会涉及到类型值的截断(大范围变为小范围可能涉及到值的缩小)。
  2. 虽然直接把一个整数值转换为一个string类型的值是可行的,但值得关注的是,被转换
    的整数值应该可以代表一个有效的 Unicode 代码点,否则转换的结果将会是"�"(仅由高亮的问号组成的字符串值)。具体关于Unicode代码点的解释可以参考下面阐述。
  3. string类型与各种切片类型之间的互转需要遵守类型编码规则,如UTF-8编码或者其他形式。

         代码展示:

package mainimport ("fmt""strconv"
)func main() {// 类型转换范围限定演练srcNum := int16(-255)dstNum := int8(srcNum)fmt.Printf("srcNum:%d, dstNum:%d\n", srcNum, dstNum)/**Go语言中负数以补码的形式存在,补码:源码求反+1-255 :1111111100000001从16位转为8位,需要高位截断变为00000001,由于最高位是0所以表示正数,所以是1*//**Go中有效的Unicode代码点是什么???在将一个整数值转换为字符串时,这个整数应该是一个有效的 Unicode 代码点的值。Unicode 是一个字符编码标准,它为世界上大多数的文字系统提供了一个唯一的码位。每个 Unicode 代码点都对应一个字符。在计算机中,字符通常以字节的形式存储,而每个字节可以表示 0 到 255 之间的整数值。当一个整数超出了这个范围,或者它不是一个有效的 Unicode 代码点时,尝试将它转换为字符串可能会导致无法正确显示该字符,从而出现替代字符,通常是 ""(一个黑色菱形,中间有一个问号)。例如,在 UTF-8 编码中,一个字符可能由一到四个字节表示。如果一个整数对应于一个超出常用 Unicode 字符范围的值(比如大于 0x10FFFF),或者它是一个用于表示字符属性的码点(比如一些控制字符),那么它可能无法被正确地转换为一个可打印的字符。在 Go 语言中,如果你使用 string() 函数将一个整数值转换为字符串,并且该值超出了有效的 Unicode 代码点范围,你可能会得到一个替代字符。为了避免这个问题,你应该确保转换的整数值在有效的 Unicode 范围内(通常是 0 到 0x10FFFF)。*/fmt.Println(string(65))fmt.Println(string(37))fmt.Println(string(-1))/**正确的将整数转为字符串应该使用Go中提供的转换工具如:strconv.Itoa()\strconv.FormatInt()*/num := -1fmt.Println(strconv.Itoa(num))fmt.Println(strconv.FormatInt(int64(num), 10))
}

        结果展示:

Unicode代码点

        在将一个整数值转换为字符串时,这个整数应该是一个有效的 Unicode 代码点的值。Unicode 是一个字符编码标准,它为世界上大多数的文字系统提供了一个唯一的码位。每个 Unicode 代码点都对应一个字符。 在计算机中,字符通常以字节的形式存储,而每个字节可以表示 0 到 255 之间的整数值。当一个整数超出了这个范围,或者它不是一个有效的 Unicode 代码点时,尝试将它转换为字符串可能会导致无法正确显示该字符,从而出现替代字符,通常是 ""(一个黑色菱形,中间有一个问号)。 例如,在 UTF-8 编码中,一个字符可能由一到四个字节表示。如果一个整数对应于一个超出常用 Unicode 字符范围的值(比如大于 0x10FFFF),或者它是一个用于表示字符属性的码点(比如一些控制字符),那么它可能无法被正确地转换为一个可打印的字符。 在 Go 语言中,如果你使用 string() 函数将一个整数值转换为字符串,并且该值超出了有效的 Unicode 代码点范围,你可能会得到一个替代字符。为了避免这个问题,你应该确保转换的整数值在有效的 Unicode 范围内(通常是 0 到 0x10FFFF)。

        Unicode代码点可以借助ASCII码表理解,如A对应的整数类型值为65,这一部分可以借助上面代码理解。

类型别名、潜在类型

        在Go语言中,可以使用关键字type声明自定义的各种类型,这些类型必须在Go语言基本类型和高级范畴之内。下面介绍类型别名以及潜在类型。

type Mystring = string

       这条声明语句表示,MyString是string类型的别名类型。顾名思义,别名类型与其源类型的
区别恐怕只是在名称上,它们是完全相同的。

        源类型与别名类型是一对概念,是两个对立的称呼。别名类型主要是为了代码重构而存在的。在Go语言中已经存在的有别名类型如:byte是unit8的类型别名,rune是int32的类型别名。

type Mystring string

        上述Mystring和string是两个不同的类型,Mstring是一个新的类型,不同于其他任何类型。

        这种方式也可以被叫做对类型的再定义。我们刚刚把string类型再定义成了另外一个类型Mystring。对于这里的类型再定义来说,string可以被称为Mystring的潜在类型。潜在类型的含义:
        某个类型在本质上是哪个类型或者是哪个类型的集合。潜在类型相同的不同类型的值之间是可以进行类型转换的。        

        因此,Mystring类型的值与string类型的值可以使用类型转换表达式进行互转。但对于集合类的类型[]Mystring与[]string来说这样做却是不合法的,因为[]Mystring与[]string的潜在类型不同,分别是Mystring和string。另外,即使两个类型的潜在类型相同,它们的值之间也不能进行判等或比较,它们的变量之间也不能赋值。

        代码演示:

 

package mainimport ("fmt"
)// 潜在类型
type MyString string// 类型别名
type MyString2 = stringfunc main() {var name MyStringname = "zhang san"var copyName string/**潜在类型相同的不同类型的值之间是可以进行类型转换的。即使两个类型的潜在类型相同,但这两个类型对应的变量之间也不能进行判等或者比较,也不能进行赋值,只能进行类型转换copyName = name 不允许的操作*/copyName = string(name)fmt.Println(name)fmt.Println(copyName)fmt.Println("=========================")var name2 MyString2name2 = "lisi"var copyName2 stringcopyName2 = name2fmt.Println(name2)fmt.Println(copyName2)
}

  类型别名的意义

        对于大型的代码库来说,能够重构其整体结构是非常重要的,包括修改某些 API 所属的包。大型重构应该支持一个过渡期:从旧位置和新位置获得的 API 都应该是可用的,而且可以混合使
用这些 API 的引用。Go 已经为常量、函数或变量的重构提供了可行的机制,但是并不支持类
型。类型别名提供了一种机制,它可以使得 oldpkg.OldType 和 newpkg.NewType 是相同的,并且引用旧名称的代码与引用新名称的代码可以互相操作。

        考虑将一个类型从一个包移动到另一个包中的情况,比如从 oldpkg.OldType 到newpkg.NewType。可以在包 oldpkg 中指定一个新类型的别名 type OldType = newpkg.NewType,这样以前的代码都无需修改。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 毕业设计选题:基于ssm+vue+uniapp的校园失物招领小程序
  • 《MATLAB项目实战》,专栏目录和介绍
  • 华为驱动未卸载导致内存完整性无法开启,导致lol卡顿,后台十几个重复进程
  • Pytorch实现Transformer
  • React Native 在 build 的时候如果出现 `babel.config.js` 配置文件的错误
  • 量子计算如何引发第四次工业革命——解读加来道雄的量子物理观
  • http代理池子大小要如何判断?
  • 后端开发刷题 | 最小的K个数(优先队列)
  • Centos中dnf和yum区别对比
  • 移动开发(三):使用.NET MAUI打包第一个安卓APK完整过程
  • Qt:关于16进制数转化那些事
  • 软件测试面试八股文(含文档)
  • 算法练习题26——等差素数数列 (2017年蓝桥杯试题B)
  • 业务数据批量插入数据库实践
  • Java读取输入流(比如文件、网络资源等)并将数据输出到本地文件
  • 30秒的PHP代码片段(1)数组 - Array
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • JS+CSS实现数字滚动
  • Just for fun——迅速写完快速排序
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Python语法速览与机器学习开发环境搭建
  • Vim Clutch | 面向脚踏板编程……
  • Vue.js-Day01
  • 动态魔术使用DBMS_SQL
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 扑朔迷离的属性和特性【彻底弄清】
  • 前嗅ForeSpider采集配置界面介绍
  • 浅谈web中前端模板引擎的使用
  • 如何用vue打造一个移动端音乐播放器
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 我的业余项目总结
  • 学习ES6 变量的解构赋值
  • 移动端 h5开发相关内容总结(三)
  • 原生Ajax
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • ​数据结构之初始二叉树(3)
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (8)STL算法之替换
  • (LeetCode) T14. Longest Common Prefix
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (译) 函数式 JS #1:简介
  • (转)甲方乙方——赵民谈找工作
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .net core Swagger 过滤部分Api
  • .Net Core 中间件验签
  • //解决validator验证插件多个name相同只验证第一的问题
  • /bin/bash^M: bad interpreter: No such file or directory
  • @Autowired和@Resource装配
  • @EnableWebSecurity 注解的用途及适用场景