# Go 数据类型和类型转换
Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、`map`、通道(channel)等。Go 语言的基本类型和其他语言大同小异。
## 整型
整型分为以下两个大类: 按长度分为:int8、int16、int32、int64 对应的无符号整型:uint8、uint16、uint32、uint64
其中,uint8 就是我们熟知的 byte型,int16 对应 C语言中的 short型,int64对应C语言中的 long型。
<img src = 'https://static.studygolang.com/190824/5347c32cc4c5eb6e58c0be3ae63b321f.png' width="70%"></img>
## 特殊整型
<img src = 'https://static.studygolang.com/190824/067a6a1cc1dabd7ff15de1da59ed7d4f.png' width="60%"></img>
**注意**: 在使用int和 uint类型时,不能假定它是32位或64位的整型,而是考虑int和uint可能在不同平台上的差异。
**注意事项**:获取对象的长度的内建len()函数返回的长度可以根据不同平台的字节长度进行变化。实际使用中,切片或 map 的元素数量等都可以用int来表示。在涉及到二进制传输、读写文件的结构描述时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用int和 uint。
## 八进制&十六进制
Go语言中无法直接定义二进制数,关于八进制和十六进制数的示例如下:
```go
package main
import "fmt"
func main(){
// 十进制
var a int = 10
fmt.Printf("%d \n", a) // 10
fmt.Printf("%b \n", a) // 1010 占位符%b表示二进制
// 八进制 以0开头
var b int = 077
fmt.Printf("%o \n", b) // 77
// 十六进制 以0x开头
var c int = 0xff
fmt.Printf("%x \n", c) // ff
fmt.Printf("%X \n", c) // FF
}
```
## 浮点型
Go语言支持两种浮点型数:float32和float64。这两种浮点型数据格式遵循IEEE 754标准: float32 的浮点数的最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32。 float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64。
打印浮点数时,可以使用fmt包配合动词%f,代码如下:
``` go
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("%f\n", math.Pi)
fmt.Printf("%.2f\n", math.Pi)
}
```
## 复数
**complex64和complex128**
```go
var c1 complex64
c1 = 1 + 2i
var c2 complex128
c2 = 2 + 3i
fmt.Println(c1)
fmt.Println(c2)
```
> 复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部和虚部为64位。
## 布尔型
Go语言中以 bool 类型进行声明布尔型数据,布尔型数据只有true(真)和false(假)两个值。
**注意**:
- 布尔类型变量的默认值为false。
- Go 语言中不允许将整型强制转换为布尔型.
- 布尔型无法参与数值运算,也无法与其他类型进行转换。
## 字符串
Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)一样。 Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为双引号(")中的内容,可以在Go语言的源码中直接添加非ASCII码字符,例如:
```go
s1 := "hello"
s2 := "你好"
```
### 字符串转义
<img src = 'https://static.studygolang.com/190824/5bb68d5dc48df2606ff34cc027eef7ab.png' width="60%"></img>
### 多行字符串
Go语言中要定义一个多行字符串时,就必须使用反引号字符:
反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。
```go
s1 := `第一行
第二行
第三行
`
fmt.Println(s1)
```
### 字符串的常用操作
<img src = 'https://static.studygolang.com/190824/3a84729d8ea5d8310a55e09c1c59fff3.png' width="70%"></img>
## byte和rune类型
组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来,如:
```go
var a := '中'
var b := 'x'
```
Go 语言的字符有以下两种:
- uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
- rune类型,代表一个 UTF-8字符。
当需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型实际是一个int32。
Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾。
```go
// 遍历字符串
func traversalString() {
s := "hello中国"
for i := 0; i < len(s); i++ { //byte
fmt.Printf("%v(%c) ", s[i], s[i])
}
fmt.Println()
for _, r := range s { //rune
fmt.Printf("%v(%c) ", r, r)
}
fmt.Println()
}
```
打印结果:
```
104(h) 101(e) 108(l) 108(l) 111(o) 228(ä) 184(¸) 173(•) 229(å) 155(•) 189(½)
104(h) 101(e) 108(l) 108(l) 111(o) 20013(中) 22269(国)
```
因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。
字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成。
### 修改字符串
要修改字符串,需要先将其转换成[]rune或[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。
```go
func changeString() {
s1 := "big"
// 强制类型转换
byteS1 := []byte(s1)
byteS1[0] = 'p'
fmt.Println(string(byteS1))
s2 := "白萝卜"
runeS2 := []rune(s2)
runeS2[0] = '红'
fmt.Println(string(runeS2))
}
```
## 类型转换
Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用。
强制类型转换的基本语法如下:
```
T(表达式)
```
其中,T表示要转换的类型。表达式包括变量、复杂算子和函数返回值等.
比如计算直角三角形的斜边长时使用math包的Sqrt()函数,该函数接收的是float64类型的参数,而变量a和b都是int类型的,这个时候就需要将a和b强制类型转换为float64类型。
## 练习题
**1、编写代码分别定义一个整型、浮点型、布尔型、字符串型变量,使用fmt.Printf()搭配%T分别打印出上述变量的值和类型**
**2、编写代码统计出字符串"hello沙河小王子"中汉字的数量**
## 笔记
```go
/**
* @Author: Weizhen
* @Date: 2019-08-24 10:18
**/
package main
import (
"fmt"
"math"
)
// 遍历字符串
func traversal_string() {
s := "hello中国"
for i := 0; i < len(s); i++ { //byte
fmt.Printf("%v(%c) ", s[i], s[i])
}
fmt.Println()
for _, r := range s { //rune
fmt.Printf("%v(%c) ", r, r)
}
fmt.Println()
}
// 修改字符串
func changeString() {
s1 := "big"
// 强制类型转换
byteS1 := []byte(s1)
byteS1[0] = 'p'
fmt.Println(string(byteS1))
s2 := "白萝卜"
runeS2 := []rune(s2)
runeS2[0] = '红'
fmt.Println(string(runeS2))
}
func main() {
fmt.Println("整型 ----> ")
var a int = 10
var b int = 077
var c int = 0xff
fmt.Printf("%d \n",a) // 10
fmt.Printf("%b \n",a) // 1010 占位符 %b 表示二进制
fmt.Println(a, b, c) // 10 63 255
fmt.Printf("%o\n", b) // 77
fmt.Printf("%x\n", c) // ff
fmt.Printf("%p\n", &c) // 求c变量的内存地址 0xc000016060
fmt.Println("浮点型 ----> ")
fmt.Printf("%f \n",math.Pi) // 3.141593
fmt.Printf("%.2f \n",math.Pi) // 3.14
fmt.Println(math.MaxFloat64) // 1.7976931348623157e+308
fmt.Println(math.MaxFloat32) // 3.4028234663852886e+38
fmt.Println("复数 ----> ")
var c1 complex64
c1 = 1 + 2i
fmt.Println(c1) // (1+2i)
fmt.Println("字符串 --->")
fmt.Println("str := \"c:\\Code\\lesson1\\go.exe\"") // 打印一个路径字符串
var s1 = `第一行
第二行/n \n`
fmt.Println(s1) // 打印多行字符串,转义字符均无效,会原样输出
traversal_string() // 引用遍历上面字符串的函数
changeString()
}
```
参考来源
> [原文参考](https://www.liwenzhou.com/posts/Go/12_datatype/ "李文周")
> [Typeof参考](https://studygolang.com/articles/14269 )
有疑问加站长微信联系(非本文作者)