第3章 Go语言的数据类型 在前面已经用到一些数据类型,如整数类型和字符串类型等,本章重点介绍基本数据类型。 微课视频 3.1Go语言的数据类型概述 Go语言的数据类型可以分为基本数据类型、复合数据类型和自定义数据类型,如图31所示。 图31Go语言的数据类型 说明如下: (1) 基本数据类型是Go语言的内置数据类型,主要分为布尔类型、数值类型和字符串类型,其中数值类型又分为整数类型和浮点类型。 (2) 复合数据类型是由基本数据类型组合出来的数据类型,如图32所示。复合数据类型将在第5章详细介绍,这里不再赘述。 图32复合数据类型 (3) 自定义数据类型是用户自定义的数据类型,需要通过type关键字定义。 微课视频 3.2整数类型 Go语言中整数类型分为以下两类。 (1) 与平台无关整数类型:如图33所示,数据占用的内存空间与平台无关,占用空间分别为8位、16位、32位和64位,又可分为有符号整数和无符号整数。 图33与平台无关整数类型 (2) 与平台相关整数类型:如图34所示,数据类型占用的内存空间是由系统决定的。 图34与平台相关整数类型 整数的默认类型是int。 这些数据类型说明如表31所示。 表31数据类型说明 数据类型占用空间(单位: 位)数据类型占用空间(单位: 位) int88uint1616 int1616uint3232 int3232uint6464 uint与平台相关byte等价于uint8 int与平台相关uintptr无符号的指针 int6464rune等价于int32 uint88 Go语言中的整数类型默认是int,例如19表示的是十进制整数。其他进制(如二进制、八进制和十六进制)整数表示方式分别如下: (1) 二进制数: 以0b或0B为前缀,注意0是阿拉伯数字,例如0B10011表示十进制数19。 (2) 八进制数:以0o或0O为前缀,第一个字符是阿拉伯数字0,第二个字符是英文字母o或O,例如0O23表示十进制数19。 (3) 十六进制数: 以0x或0X为前缀,注意0是阿拉伯数字,例如0X13表示十进制数19。 示例代码如下: // 3.2 整数类型 package main import "fmt" func main() { // 声明变量 var int0 = 19 // 十进制表示的19 var int1 int8 = 0b10011 // 二进制表示的19 var int2 int16 = 0o23 // 八进制表示的19 var int3 int32 = 0x13 // 十六进制表示的19 fmt.Printf("十进制数 %d\n", int0) fmt.Printf("int0的类型 : %T\n", int0) fmt.Printf("二进制数 %b\n", int1) fmt.Printf("int1的类型 : %T\n", int1) fmt.Printf("八进制制数 %o\n", int2) fmt.Printf("int2的类型 : %T\n", int2) fmt.Printf("十六进制制数 %x\n", int3) fmt.Printf("int3的类型 : %T\n", int3) } 上述代码执行结果如下: 十进制数 19 int0的类型 : int 二进制数 10011 int1的类型 : int8 八进制制数 23 int2的类型 : int16 十六进制制数 13 int3的类型 : int32 微课视频 3.3浮点类型 浮点类型主要用来存储小数。Go语言提供了两种精度的浮点数: 32位浮点数float32和64位浮点数float64,默认类型是float64。 浮点类型可以使用小数表示,也可以使用科学记数法表示,科学记数法中会使用大写或小写的e表示10的指数,如e2表示102。 示例代码如下: // 3.3 浮点类型 package main import "fmt" func main() { // 声明变量 var float1 = 0.0 // 浮点数0 var float2 float32 = 2.154327 var float3 float64 = 2.1543276e2 // 科学记数法表示浮点数 var float4 = 2.1543276e-2 // 科学记数法表示浮点数 fmt.Printf("float1: %f\n", float1) fmt.Printf("float2的类型 : %T\n", float2) fmt.Printf("float3的类型 : %f\n", float3) fmt.Printf("float3的类型 : %T\n", float3) fmt.Printf("float4的类型 : %f\n", float4) fmt.Printf("float4的类型 : %T\n", float4) } 上述代码执行结果如下: float1: 0.000000 float2的类型 : float32 float3的类型 : 215.432760 float3的类型 : float64 float4的类型 : 0.021543 float4的类型 : float64 微课视频 3.4复数类型 复数在数学中是非常重要的概念,无论是理论物理学,还是电气工程实践中都经常使用。很多计算机语言都不支持复数,而Go语言是支持复数的,这使得Go语言能够很好地用于科学计算。 Go语言中的复数类型有两种: complex128(64位实部和64位虚部)和complex64(32位实部和32位虚部),其中complex128为默认的复数类型。 示例代码如下: // 3.4 复数类型 package main import "fmt" func main() { // 声明变量 var complex1 complex128 = complex(2, -3)// 声明实部为2,虚部为-3的复数 var complex2 complex64 = complex(9, 2) // 通过complex()函数创建复数,该函数第 // 1个参数是实部,第2个参数是虚部 fmt.Println(complex1) fmt.Println(complex2) } 上述代码执行结果如下: (2-3i) (9+2i) 微课视频 3.5布尔类型 Go语言中的布尔类型为bool,它只有两个值: true和false。 示例代码如下: // 3.5 布尔类型 package main import "fmt" func main() { // 声明变量 var male bool = true var female = false fmt.Println(male) fmt.Println(female) fmt.Printf("male的类型 : %T\n", male) fmt.Printf("female的类型 : %T\n", female) 上述代码执行结果如下: true false male的类型 : bool female的类型 : bool 微课视频 3.6类型转换 学习了前面的数据类型后,读者可能会思考一个问题:数据类型之间是否可以相互转换呢?数据类型的转换情况比较复杂。在基本数据类型中,数值类型之间可以互相转换,但字符类型和布尔类型不能与数值类型相互转换。 Go语言中不存在隐式类型转换,所有类型都必须显式类型转换。 显式类型转换语法格式如下: 目标数据类型(表达式) 显式转换示例代码如下: // 3.6 类型转换 package main import "fmt" func main() { // 声明变量 var sum int = 17 var count int = 5 var mean float32 mean = float32(sum) / float32(count)① fmt.Printf("mean : %f\n", mean) var long1 int64 = 999999999999 var int1 int32 = int32(long1) // 将int64类型强制转换为int32类型,精度丢失② fmt.Println(int1) // -727379969 var float1 = 3.456 var int2 = int32(float1) // 小数部分被截掉 ③ fmt.Println(int2) } 上述代码第①行将sum变量转换为float32数据类型,将count变量转换为float32数据类型。 需要注意的是,代码第②行经过类型转换后,原本的999999999999变成了负数。当字节长度大的数值转换为字节长度小的数值时,大数值的高位被截掉,这样就会导致数据精度丢失。 代码第③行浮点数转换为整数时,小数部分会被截掉。 上述代码执行结果如下: mean : 3.400000 -727379969 3.7字符串类型 一个字符串是一个不可改变的字节序列,其中每个字符均采用UTF8编码,UTF8编码可以表示世界上存在的任何语言的字符。 微课视频 3.7.1字符串表示 Go语言中的字符串是用双引号("")包裹起来表示的。 示例代码如下: // 3.7.1 字符串表示 package main import "fmt" func main() { // 声明字符串变量 var s1 = "Hello" // 字符串拼接 var s2 = s1 + "World." // 采用Unicode编码表示字符串 var s3 = "\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064" //汉字字符串 const s4 = "世界你好" fmt.Println(s2) fmt.Println(s3) fmt.Println(s4) // 通过len()函数获得字符串长度 fmt.Printf("s1字符串长度:%d\n", len(s1)) fmt.Printf("%c\n", s1[0]) } 上述代码执行结果如下: HelloWorld. Hello World 世界你好 s1字符串长度:5 微课视频 3.7.2字符转义 如果想在字符串中包含一些特殊的字符,例如换行符、制表符等,在普通字符串中则需要转义,前面要加上反斜线“\”,这称为字符转义。用于转义的字符称为转义符,表32所示是常用的转义符。 表32常用的转义符 转义符Unicode编码说明 \t \u0009水平制表符tab \n \u000a换行 \r \u000d回车 \"\u0022双引号 \' \u0027单引号 \\\u005c反斜线 示例代码如下: // 3.7.2 字符转义 package main import "fmt" func main() { // 声明变量 var s1 = "\"世界\"你好!" // 转义双引号 var s2 = "Hello\t World" // 转义制表符 var s3 = "Hello\\ World" // 转义反斜线 var s4 = "Hello\n World" // 转义换行符 fmt.Println("s1", s1) fmt.Println("s2", s2) fmt.Println("s3", s3) fmt.Println("s4", s4) } 上述代码执行结果如下: s1 "世界"你好! s2 Hello World s3 Hello\ World s4 Hello World 微课视频 3.7.3原始字符串 如果字符串中有很多特殊字符都需要转义,使用转义符就非常麻烦,也不美观。这种情况下可以使用原始字符串(rawstring)表示。原始字符串使用反引号(`)包裹起来,其中的特殊字符不需要转义,按照字符串的本来“面目”呈现。例如在Windows系统中,tony用户Documents文件夹下面的\readme.txt文件的路径表示如下: C:\Users\tony\Documents\readme.txt 由于文件路径分隔用反斜线表示,在程序代码中用普通字符串表示时需要将反斜线进行转义,而路径中有很多反斜线,所以很麻烦。如果采用原始字符串,就比较简单了,示例代码如下: // 3.7.3 原始字符串 package main import "fmt" func main() { // 声明变量 // 采用普通字符串表示文件路径,其中的反斜线需要转义 const filepath1 = "C:\\Users\\tony\\Documents\\readme.txt" // 采用原始字符串表示文件路径,其中的反斜线不需要转义 const filepath2 = `C:\Users\tony\Documents\readme.txt` fmt.Println("路径1:", filepath1) fmt.Println("路径2:", filepath2) // 声明长字符串s1 const s1 = ` 《将进酒》 君不见黄河之水天上来,奔流到海不复回。 君不见高堂明镜悲白发,朝如青丝暮成雪。 人生得意须尽欢,莫使金樽空对月。 天生我材必有用,千金散尽还复来。 烹羊宰牛且为乐,会须一饮三百杯。 岑夫子,丹丘生,将进酒,杯莫停。 与君歌一曲,请君为我倾耳听。 钟鼓馔玉不足贵,但愿长醉不复醒。 古来圣贤皆寂寞,惟有饮者留其名。 陈王昔时宴平乐,斗酒十千恣欢谑。 主人何为言少钱,径须沽取对君酌。 五花马,千金裘,呼儿将出换美酒, 与尔同销万古愁。 ` fmt.Println("长字符串s1:", s1) } 微课视频 3.7.4操作字符串的常用函数 Go语言的strings包提供了很多操作字符串的函数,下面介绍几个常用的操作字符串函数。 (1) func Contains(s, substr string) bool: 判断字符串s中是否包含字符串substr。 (2) func Replace(s, old, new string, n int) string: 用string替换字符串s中的old字符串,并返回替换后的字符串,其中参数n是指定替换的个数。 (3) func ToUpper(s string) string: 将字符串s中的所有字母转换为大写字符。 (4) func ToLower(s string) string: 将字符串s中的所有字母转换为小写字符。 (5) func Split(s, sep string) []string: 将字符串s按照sep进行分割,返回字符切片。 // 3.7.4 操作字符串的常用函数 package main import ( "fmt" "strings" // 导入字符串包 ) func main() { // 短变量声明字符串 string1 := "Hello" string2 := "hello" result := string1 == string2① fmt.Println(result) //输出false // 短变量声明字符串 text1 := "Go Programming" substring1 := "Go" // 在text1中查找是否包含substring1字符串 result = strings.Contains(text1, substring1) ② fmt.Println(result) // 输出true text2 := "car" fmt.Println("旧字符串:", text2) // 把r替换为t replacedText := strings.Replace(text2, "r", "t", 1) ③ fmt.Println("新字符串:", replacedText) // 输出cat text3 := "I Love Golang" // 转换为大写 text4 := strings.ToUpper(text3) ④ fmt.Println(text4) // 输出I LOVE GOLANG // 转换为小写 var text5 = strings.ToLower(text3)⑤ fmt.Println(text5) // 输出i love golang // 用空格分割字符串" " splittedString := strings.Split(text3, " ") ⑥ fmt.Println(splittedString) // 输出[I Love Golang] } 上述代码第①行通过“==”比较字符串是否相等。 代码第②行通过字符串的Contains()方法判断是否包含子字符串。 代码第③行通过字符串的Replace()方法替换字符。 代码第④行将字符串中的所有字母转换为大写,代码第⑤行将字符串中的所有字母转换为小写。 代码第⑥行通过字符串的Split()方法分割字符串,其中第1个参数是要被分割的字符串,第2个参数是分割字符串,返回字符串数组。 上述代码执行结果如下: false true 旧字符串: car 新字符串: cat I LOVE GOLANG i love golang [I Love Golang] 3.8动手练一练 选择题 (1) 下面哪行代码在编译时不会出现警告或错误信息?() A. var f = 1.3B. var f int = 13C. f:= 13D. var f int = 13 (2) int8的取值范围是()。 A. -128~127B. -256~256 C. -255~256D. 依赖于计算机本身硬件 (3) 下列选项中不是Go语言的基本数据类型是()。 A. short B. int16C. intD. float (4) 下列选项中关于原始字符串的说法正确的是()。 A. 需使用单引号(')包裹起来 B. 需使用双引号(")包裹起来 C. 需使用三重单引号(''')包裹起来 D. 需使用反引号(`)包裹起来