Go-基本数据类型+数据类型转换
1 Golang数据类型分类
基本数据类型
数值型
整数型:int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、byte
浮点型:float32、float64
布尔型(bool):true、false
字符型(golang没有单独的字符型,使用byte来保存单个字母字符)
字符串(string)
派生数据类型/复杂数据类型
指针
数组
结构体
管道
函数
切片
接口
map
2 整数类型
2.1 有符号整数类型
类型 | 有无符号 | 占用存储空间 | 二进制位 | 表数范围 |
---|---|---|---|---|
int8 | 有 | 1字节 | 8位(1位符号+7位二进制) | -2^7 ~ 2^7-1(-128~127) |
int16 | 有 | 2字节 | 16位(1位符号+15位二进制) | -2^15 ~ 2^15-1(-32768~32767) |
int32 | 有 | 4字节 | 32位(1位符号+31位二进制) | -2^31 ~ 2^31-1 |
int64 | 有 | 8字节 | 64位(1位符号+63位二进制) | -2^64 ~ 2^64-1 |
eg:127怎么算出来的呢?
正数-->第一位(符号位)为0
01111111-->转化为10进制:
1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
= 64 + 32 + 16 + 8 + 4 + 2 + 1
= 127
2.1.1 golang语言中的原码、反码、补码
- 在golang语言中正数在计算机中的二进制还是原值(即原码),负数在计算机中存储的是补码,所以我们讨论补码只考虑负数;
- 原码就是负数的绝对值转换成的二进制码
- 反码就是原码每位取反得到的二进制码
- 补码就是反码加一得到的二进制码
- 符号位单算,负数的符号位为"1"
eg:-128怎么算来的呢?
-128的原码为 10000000 反码为 01111111 补码为 10000000
正好负数-->第一位(符号位)为1,所以
10000000= -128
00000000= 0
11111111= -127
2.2 无符号整数类型
类型 | 有无符号 | 占用存储空间 | 二进制位 | 表数范围 |
---|---|---|---|---|
uint8 | 无 | 1字节 | 8位 | 0 ~ 2^8-1(0~255) |
uint16 | 无 | 2字节 | 16位 | 0 ~ 2^16-1 |
uint32 | 无 | 4字节 | 32位 | 0 ~ 2^32-1 |
uint64 | 无 | 8字节 | 64位 | 0 ~ 2^64-1 |
eg:255怎么算出来的
11111111-->转化为10进制:
1*2^7 + 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
= 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 255
2.3 其他整数类型
类型 | 有无符号 | 占用存储空间 | 二进制位 | 表数范围 |
---|---|---|---|---|
int(默认) | 有 | 32位系统4字节 64位系统8字节 |
32-1位 64-1位 |
-2^31 ~ 2^31-1 -2^63 ~ 2^63-1 |
uint | 无 | 32位系统4字节 64位系统8字节 |
32-1位 64-1位 |
0 ~ 2^32-1 0 ~ 2^64-1 |
rune | 有 | 等价int32 | 32-1位 | -2^31 ~ 2^31-1 |
byte | 无 | 等价uint8 | 8位 | 0 ~ 2^8-1 |
测试
package main
import (
"fmt"
"unsafe"
)
func main() {
var a int = -128
var b int8 = -128
fmt.Println("a= ", a, " a占用的字节数", unsafe.Sizeof(a))
fmt.Println("b= ", b, " b占用的字节数", unsafe.Sizeof(b))
}
----------------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\int.go
a= -128 a占用的字节数 8
b= -128 b占用的字节数 1
PS C:\Goproject\src\gocode\project01\main>
3 浮点类型
3.1 只有两类浮点类型float32、float64
类型 | 占用存储空间 | 二进制位 | 表数范围 |
---|---|---|---|
float32 | 4字节 | 32位 | -3.403E38 ~ 3.403E38 |
float64(默认) | 8字节 | 64位 | -1.798E308 ~ 1.798E308 |
示例
package main
import (
"fmt"
"unsafe"
)
func main() {
//定义浮点类型的数据
var a float32 = 3.14
fmt.Println("a= ", a, " a占用的字节数", unsafe.Sizeof(a))
//可以赋值为负的浮点数
var b float32 = -3.14
fmt.Println("b= ", b, " b占用的字节数", unsafe.Sizeof(b))
//可以用科学计数法表示,E可大写可小写
var c float32 = -314e-2
fmt.Println("c= ", c, " c占用的字节数", unsafe.Sizeof(c))
var d float32 = -3.14e+2
fmt.Println("d= ", d, " d占用的字节数", unsafe.Sizeof(d))
var e float32 = 314e-2
fmt.Println("e= ", e, " e占用的字节数", unsafe.Sizeof(e))
var f float64 = 314e-2
fmt.Println("f= ", f, " f占用的字节数", unsafe.Sizeof(f))
//浮点数可能会有精度损失,float64的精度损失会小一点
var g float64 = -3.140000000625
fmt.Println("g= ", g, " g占用的字节数", unsafe.Sizeof(g))
var h float32 = -3.140000000625
fmt.Println("h= ", h, " h占用的字节数", unsafe.Sizeof(h))
//Golang中默认浮点类型为float64
var i = 3.14
fmt.Printf("i的默认数据类型为:%T", i)
}
--------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\int.go
a= 3.14 a占用的字节数 4
b= -3.14 b占用的字节数 4
c= -3.14 c占用的字节数 4
d= -314 d占用的字节数 4
e= 3.14 e占用的字节数 4
f= 3.14 f占用的字节数 8
g= -3.140000000625 g占用的字节数 8
h= -3.14 h占用的字节数 4
i的默认数据类型为:float64
PS C:\Goproject\src\gocode\project01\main>
4 布尔型
- golang 中以bool关键字声明布尔类型数据,布尔型的值只可以是true 或者 false。代表条件成立(真)或条件不成立(假)
- 布尔类型变量的默认值为 false
- golang 中不允许将整型强制转换为布尔型
- 布尔型无法参与数值运算,也无法与其他类型进行转换
5 字符类型
- 在Golang语言中没有专门的字符类型,如果要存储单个字符(字母),一般声明为byte类型来保存,所以一个字符在golang语言中的本质可以理解为一个特定的整数;
- 值为汉字等字符变量可以声明为int类型,因为byte类型不够用
- 字符常量用单引号括起来的单个字符
- golang语言中允许使用转译字符''来将其后面的字符转变为特殊字符(\n;\t;\r等)
5.1 示例
package main
import "fmt"
func main() {
var a1 byte = 'a'
var a2 byte = '0' //字符0
//当我们直接输出byte值,就是输出了对应的字符的码值
fmt.Println("a1= ", a1)
fmt.Println("a2= ", a2)
fmt.Println("a1+a2=", a1+a2)
//如果我们希望输出对应的字符,需要使用格式化输出
fmt.Printf("a1=%c a2=%c", a1, a2)
var a3 int = '杜'
fmt.Printf("a3=%c a3对应的码值=%d", a3, a3)
}
----------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\var.go
a1= 97
a2= 48
a1+a2= 145
a1=a a2=0a3=杜 a3对应的码值=26460
PS C:\Goproject\src\gocode\project01\main>
5.2 字符编码:ASCII 与 UTF-8 编码
- 在计算机内部,所有的数据都是以二进制0、1表示,每个二进制位为一个比特(Bit),但是一个Bit能表示的信息太少,所以一个最小的操作单位应该包含多个多个比特,起初这个单位并没有统一标准,有4比特一个单位的,也有7个、8个比特一个单位的,但是最终还是8比特单位一统江湖,这就有了后来的 1Byte= 8Bit。
- 为什么需要对字符编码呢?如果没有字符编码,通过计算机进行聊天时,可能是这样的:A->B:01101000 01101001,B收到信息之后可能就需要查字典去了,那为什么计算机不帮我查好呢!所以编码就是二进制与字符的转换关系。
5.2.1 ASCII编码
- 1967年美国制定了一套编码规范,其中规定了 128 个字符与二进制的对应关系,称之为 ASCII 编码,二进制范围是 0-127:[00000000,011111111],可以看出来最高位没有使用。
- 虽然 ASCII 规范出来了,但是存在很多不足,主要原因是它所包含的字符集太小,只有拉丁字母、阿拉伯字符、英文标点和一些控制字符,此时欧洲人第一个站出来表示不高兴,比如意大利语的字符 Á 没法表示,正好ASCII 编码中最高位被闲置了,把这部分进行利用,将ASCII 从7位扩展成了8位,这就是扩展ASCII(EASCII)。
- 将 ASCII 编码扩展之后,欧洲人高兴了,但是其他语音还是不能处理。为了解决这些语言的编码问题,各国开始搞自己的编码,这期间产生了许多种编码格式,比如常见的汉字编码格式 GB-2312。各个国家都采用不同的编码,这样是没办法相互通信的,所以需要有一种编码,能够涵盖所有语言符号,这就是 Unicode。
5.2.2 Unicode 编码
- Unicode 也叫万国码、统一码、国际码,它是为了解决各个编码格式的不兼容问题,它为各个语言字符进行了编号,比如汉字“你”编号为 0x4f60,“好”编号为 0x597d。
- Unicode 只是对各个语言字符进行了编号,但是没有对编号如何存储、存储几个字节进行规定,还是以汉字“你”为例,它的编号是 0x4f60,最少可以用两个字节来存储,也可以用3个、4个;另一个问题是计算机怎么判断这两个字节是一个Unicode字符还是两个ASCII字符呢。基于这些问题,产生了多种 Unicode 字符集实现格式,其中就包括 UTF-8.
5.2.3 UTF-8 编码实现
- UTF-8(8-bit Unicode Transformation Format)是Unicode 的实现方式之一
- UTF-8 是以8位为一个编码单位的变长的编码方式,使用1~4个字节表示一个符号,根据不同的符号而变化字节长度
- UTF-8 是互联网上使用最广的 Unicode 实现方式
5.2.4 ASCII 与 UTF-8 编码在golang
- ASCII与UTF-8编码中每一个字符都对应一个码值(unicode十进制值),这个码值相当于一个特定的整数
- UTF-8中的字符集可以理解为包含ASCII中的字符集
- 值为ASCII表中的字符的变量可以声明为byte类型(英文字符;[0-9];[a-z];[A-Z]等)
- golang语言的编码统一使用UTF-8
在线文本转十进制UNICODE工具:http://www.mytju.com/classcode/tools/encode_utf8.asp
6 字符串(string)
- 传统字符串是由字符组成,而go的字符串是由字节组成
- golang语言的字符串的字节使用UTF-8编码标识Unicode文本
6.1 示例
package main
import "fmt"
func main() {
var student string = "du-z 25 你好"
fmt.Println(student)
}
-------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\str.go
du-z 25 你好
PS C:\Goproject\src\gocode\project01\main>
6.2 字符串使用注意
6.2.1 golang语言中string被赋值成功后,是不可以修改的
var str1 string = "du-z 25 你好"
str1[1] = 'a' //这是错误的,字符串不可变
6.2.2 字符串两种表现形式;双引号(会识别转义字符和特殊字符)或反引号(不识别转义字符和特殊字符,原生输出)
package main
import "fmt"
func main() {
var str1 string = `
package main
import "fmt"
func main() {
i := 0
loop:
if i < 5 {
fmt.Printf("%d", i)
i++
goto loop
}
}
`
fmt.Println(str1)
}
----------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\str.go
package main
import "fmt"
func main() {
i := 0
loop:
if i < 5 {
fmt.Printf("%d", i)
i++
goto loop
}
}
PS C:\Goproject\src\gocode\project01\main>
6.2.3 字符串拼接
package main
import "fmt"
func main() {
var str1 string = "hello" + " word" + //拼接时可以换行但是"+"要在上一行
" du-z"
str1 += "!!"
fmt.Println(str1)
}
----------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\str.go
hello word du-z!!
PS C:\Goproject\src\gocode\project01\main>
7 数值类型数据的转换
golang语言中不用类型的变量之间赋值时需要显示转换;golang中的数据类型不能自动转换。
7.1 基本语法
type(v)
// type--就是要转换为的数据类型(int,float32等)
// v--就是待转换的变量
// 被转换的是变量存储的数据值,变量本身的数据类型没有变化**
// int64 转 int8 没有报错,可能结果会有溢出和希望的结果不一样
7.2 示例
package main
import (
"fmt"
"unsafe"
)
func main() {
var a byte = 5
fmt.Println("float32(a)的字节数", unsafe.Sizeof(float32(a)))
fmt.Println("a的字节数", unsafe.Sizeof(a))
}
----------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\str.go
float32(a)的字节数 4
a的字节数 1
PS C:\Goproject\src\gocode\project01\main>
8 数值类型转string
8.1 两种实现方法
方法一:Sprintf
标准库fmt包verb:https://studygolang.com/pkgdoc
方法二:strconv 函数
func FormatBool(b bool) string
func FormatInt(i int64, base int) string
func FormatUint(i uint64, base int) string
func FormatFloat(f float64, fmt byte, prec, bitSize int) string
8.2 演示
package main
import (
"fmt"
"strconv"
)
func main() {
var num1 int = 88
var num2 float64 = 1.234
var b bool = true
var char byte = 'd'
var str string
//使用fmt.Sprintf方法转换为str
str = fmt.Sprintf("%d", num1)
fmt.Printf("str type is %T str=%q\n", str, str)
str = fmt.Sprintf("%f", num2)
fmt.Printf("str type is %T str=%q\n", str, str)
str = fmt.Sprintf("%t", b)
fmt.Printf("str type is %T str=%q\n", str, str)
str = fmt.Sprintf("%c", char)
fmt.Printf("str type is %T str=%q\n", str, str)
fmt.Println("-----------------------------------")
//使用strconv函数
str = strconv.FormatInt(int64(num1), 10)
//10为返回的字符串的进制,表示十进制
fmt.Printf("str type is %T str=%q\n", str, str)
str = strconv.FormatFloat(float64(num2), 'f', 10, 64)
//'f'为float数据的小数表示格式;10为控制精度;
fmt.Printf("str type is %T str=%q\n", str, str)
str = strconv.FormatBool(b)
fmt.Printf("str type is %T str=%q\n", str, str)
}
-------------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\str.go
str type is string str="88"
str type is string str="1.234000"
str type is string str="true"
str type is string str="d"
-----------------------------------
str type is string str="88"
str type is string str="1.2340000000"
str type is string str="true"
PS C:\Goproject\src\gocode\project01\main>
9 string类型转基本数据类型
9.1 使用strconv函数
func ParseBool(str string) (value bool, err error)
func ParseInt(s string, base int, bitSize int) (i int64, err error)
func ParseUint(s string, base int, bitSize int) (n uint64, err error)
func ParseFloat(s string, bitSize int) (f float64, err error)
9.2 示例
package main
import (
"fmt"
"strconv"
)
func main() {
var num1 int64
var num2 float64
var b bool
var str string
str = "true"
b, _ = strconv.ParseBool(str)
//1. 函数strconv.ParseBool(str)会返回两个值(value bool,err error)
//2. 使用匿名变量"_"忽略err
fmt.Printf("b type is %T b=%v\n", b, b)
str = "1234"
num1, _ = strconv.ParseInt(str, 10, 64)
//10代表十进制,64代表int64
fmt.Printf("num1 type is %T num1=%d\n", num1, num1)
str = "1.234"
num2, _ = strconv.ParseFloat(str, 64)
//64代表float64
fmt.Printf("num2 type is %T num2=%f\n", num2, num2)
}
------------------------------输出
PS C:\Goproject\src\gocode\project01\main> go run .\trans.go
b type is bool b=true
num1 type is int64 num1=1234
num2 type is float64 num2=1.234000
PS C:\Goproject\src\gocode\project01\main>
10 值类型和引用类型
10.1 值类型和引用类型理解
值类型 --- 值类型的变量在声明和赋值的时候,系统会在栈空间内分配一个内存空间,记录数据值;
引用类型 --- 引用类型的变量通常为一个地址(地址值);引用类型的变量在声明和赋值的时候,系统会在堆空间分配一个内存空间,记录"其他变量"(通常为值类型的变量)的地址值,这个地址值也会对应一个数据值(其他变量的值);
10.2 常见的值类型和引用类型
值类型 --- 基本数据类型、数组、和结构体struct
引用类型 --- 指针、slice切片、map、管道 channel、interface等