Go语言基础 -- 基本数据类型及类型转换

1. 整型

1.1 整型分类

  1. 有符号整型:int8int16int32int64
  2. 无符号整型:uint8uint16uint32uint64

1.2 整形的取值范围

类型 长度(字节) 默认值 说明
byte 1 0 uint8
rune 4 0 Unicode Code Point, int32
int, uint 4或8 0 32 或 64 位
int8, uint8 1 0 -128 ~ 127, 0 ~ 255,byte是uint8 的别名
int16, uint16 2 0 -32768 ~ 32767, 0 ~ 65535
int32, uint32 4 0 -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint64 8 0

1.3 常用整型的别名

  1. int8(8是表示8位, byte是int8的别名)
  2. rune是int32的别名,表示一个unicode码点

1.4 整型的底层存储

例如:int8,表示此数据类型占用空间为8位(1字节),

第一位为符号位,为0时,表示无符号, 为1时,表示有符号,剩余的7位表示数值,所以表示范围为2的-7到2的7次方-1(减得那个1是数值为0时,无需表示其正负),对于0表示时会有正0和-0,其实都是0所以负数部分就多了1个可以表示的数值

无符号的整数,特点是没有符号,所以第一位也可以表示数值本身,范围比有符号的要大一些,从0开始

1.5 整型操作

1.5.1 十进制转二,八,十六进制:

fmt.Println(strconv.FormatInt(132,2))  // 2 表示转成 二进制, 返回值为 string
fmt.Println(strconv.FormatInt(132,8))  // 8 表示转成 八进制, 返回值为 string
fmt.Println(strconv.FormatInt(132,16)) // 16 表示转成 十六进制, 返回值为 string

1.5 整型的注意事项

  1. Golang中各整数类型分为:有符号和无符号,int uint的大小和操作系统有关

  2. Golang的整形默认声明为int

  3. 如何在程序查看某个变量的字节大小和数据类型

    fmt.Printf("n1的类型为:%T",n1)    					  // 查看变量的类型(%T)
    
    fmt.Printf("n1占用的字节数是:%d",n1,unsafe.Sizeof(n1))  // 查看变量的所占用的字节数
    
  4. Golang中整型变量在使用时,遵守保小不保打的原则,即:在保证程序正确运行下,尽量使用占用空间小的数据类型,如年龄,不会为负数,最大为130+ 所以选用uint8(byte)最为合适

  5. bit 计算机中的最小存储单位,byte计算机中基本存储单元,1byte = 8bit

2. 浮点类型

2.1 浮点类型分裂

Go语言支持两种浮点型数,这两种浮点型数据格式遵循IEEE 754标准:

  1. float32,最大范围约为3.4e38,可以使用内置常量定义:math.MaxFloat32
  2. float64,最大范围约为 1.8e308,可以使用一个内置常量定义:math.MaxFloat64

2.2 浮点类型底层存储

浮点数在机器中存放的方式:浮点数 = 符号位+指数为+尾数位

示例:

3.56

//第一个字节表示符号位,第一位的1表示本浮点数为正数,.之前的是指数,.之后的是尾数
11110000111.11111111111111111000

//浮点型的存储分为三部分:符号位+指数位+尾数位,在存储过程中,精度会有丢失

2.3 注意事项

  1. 浮点类型有固定的范围和字段长度,不受具体OS(操作系统)的影响
  2. 浮点型默认声明为float64类型
  3. 浮点型常量有两种方式表示
    1. 十进制数形式:如:5.12 0.512 可以用.512表示(必须有小数点)
    2. 科学计数法形式:如:5.1234e2 = 5.12*10的2次方 5.12E-2=5.12/10的2次方
    3. 通常情况下应该使用float64,因为它比float32更准确,精度更高

2.4 复数(精度更高)

complex64
complex128
//复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部和虚部为64位。

3. 布尔类型

布尔类型也叫bool类型,只允许取值true和false,占用1字节,通常用于逻辑运算,流程控制

注意事项

  1. 布尔类型变量的默认值为false
  2. Go 语言中不允许将整型强制转换为布尔型.
  3. 布尔型无法参与数值运算,也无法与其他类型进行转换。

4. 字符类型

4.1 字节序列

Go语言中没有专门的字符型,如果要存储单个字符(字母),一般使用byte来保存

字符串就是一串固定长度的字符连接起来的字符序列. 
Go的字符串是由单个字节链接起来的,也就是说对于传统的字符串是由字符组成的,而Go的字符串不同,它是由字节组成的

4.2 单字符

func main() {
	var s1 byte = 'a'   // 如果保存的字符在ASICC表中,比如[0-1,a-z,A-Z],可以用byte类型保存,保存的是asicc码值
	var s2 byte = '0'
    var s3 int = '小'   // 小 这个汉字的asicc码值不在 byte 能表示的值以内,所以需要更换数据类型,如果用byte存储会报overflow错误
	fmt.Printf("s1的类型为: %T,值为%v,占用字节数为%d\n",s1,s1,unsafe.Sizeof(s1))
	fmt.Printf("s2的类型为: %T,值为%v,占用字节数为%d\n",s2,s2,unsafe.Sizeof(s2))
    fmt.Printf("s2的类型为: %T,值为%v,占用字节数为%d\n",s3,s3,unsafe.Sizeof(s3))
}


// 打印结果:
s1的类型为: uint8,值为97,占用字节数为1
s1的类型为: uint8,值为48,占用字节数为1
s2的类型为: int,值为23567,占用字节数为8

4.3 注意事项

  1. 字符常量是用单引号'引起来的单个字符,

    var c1 byte = 'a' 
    var c2 int = '中'
    var c3 byte = '9'
    
  2. Go中允许使用转义字符''来将其后的字符转变成特殊字符型常量

    var c3 char = '\n'      // \n 表示换行符         
    
  3. Go语言的字符使用UTF-8编码

  4. 在Go中字符的本质是一个整体,直接输出时,是该字符对应的UTF-8编码的码值

  5. 可以直接给某个变量赋一个数字,然后按格式化输出时%c会输出改数字对应的Unicode字符

  6. 字符类型是可以进行运算的,单个字符类型的底层是ascii码值,本质是个整数,因为它都对应有Unicode

4.4 byte类型和rune类型

func main() {
	s1 := "abcde真好"
	for i := 0; i < len(s1); i++ {
		fmt.Printf("第 %v个字符, 字符为: %c,ascii码值为: %v\r\n", i+1, s1[i], s1[i])
	}
	fmt.Println("rune循环开始!!!")
	for i, v := range s1 {
		fmt.Printf("第 %v个字符, 字符为: %c, utf-8码值为: %v\r\n", i+1, v, v)
	}
}

// 输出结果:
第 1个字符, 字符为: a,ascii码值为: 97
第 2个字符, 字符为: b,ascii码值为: 98
第 3个字符, 字符为: c,ascii码值为: 99
第 4个字符, 字符为: d,ascii码值为: 100
第 5个字符, 字符为: e,ascii码值为: 101
第 6个字符, 字符为: ç,ascii码值为: 231
第 7个字符, 字符为: œ,ascii码值为: 156
第 8个字符, 字符为: Ÿ,ascii码值为: 159
第 9个字符, 字符为: å,ascii码值为: 229
第 10个字符, 字符为: ¥,ascii码值为: 165
第 11个字符, 字符为: ½,ascii码值为: 189

rune循环开始!!!
第 1个字符, 字符为: a, utf-8码值为: 97
第 2个字符, 字符为: b, utf-8码值为: 98
第 3个字符, 字符为: c, utf-8码值为: 99
第 4个字符, 字符为: d, utf-8码值为: 100
第 5个字符, 字符为: e, utf-8码值为: 101
第 6个字符, 字符为: 真, utf-8码值为: 30495
第 9个字符, 字符为: 好, utf-8码值为: 22909

4.5 字符类型的底层存取过程

  1. 字符型存储到计算机中,需要将字符对应的码值(整数)找到

    1. 存储:找到汉字对应的码值,转成二进制,存储
    2. 读取:二进制转成码值,通过码值到utf8对照表中找到对应的字符,读取
  2. 字符和码值的对应关系是通过字符编码表决定的(规定死的)

  3. Go语言的编码都统一成了utf-8,非常的方便,很统一,再也没有编码乱码的问题

5. 字符串类型

5.1 字符串的概念

Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型 int、bool、float32、float64 等 一样。 Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为双引号"中的内容,可以在Go语言的源码中直接添加非ASCII码字符,例如:

s1 := "hello"
s2 := "你好"

字符串就是一串固定长度的字符连接起来的字符序列,Go的字符串是由单个字节链接起来的,Go语言的字符串的编码使用UTF-8编码表示Unicode文本

func main()  {
	var address string = "背景你好"
	fmt.Println(address)
}

5.2 字符串转义符

转义 含义
\r 回车符(返回行首)
\n 换行符(直接跳到下一行的同列位置)
\t 制表符
' 单引号
" 双引号
\ 反斜杠
func main() {
    // 打印路径,用\转义
    fmt.Println("str := \"c:\\pprof\\main.exe\"")
}

5.3 多行字符串

Go语言中要定义一个多行字符串时,就必须使用反引号字符:

func main() {
	s1 := `你好啊
我不好
`
	fmt.Println(s1)
}

反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。

5.4 字符串常用操作方法

5.4.1 求长度(字节数)

中文占3字节

func main() {
	s1 := "小明"
    fmt.Println(len(s1))
}

// 打印结果
6

5.4.2 遍历

// 未转成 []rune 切片时, 对于 北京 这两个中文, 底层是用字节来存储的
// 所以当遍历时, 北京 这两个中文可能是由 四个字符 来表示的, 无法真实的表示出 北京 这两个中文, 所以需要转成 []rune 切片


// for i
str1 := "hello北京"
newStr := []rune(str1) // 如果字符串中有中文可以将str1,转换成[]rune切片,否则会按照默认的字节遍历
for i := 0; i < len(newStr); i++ {
	fmt.Printf("第 %v 个字符, 字符为 %c, ascii码值为 %v\n", i, newStr[i], newStr[i])
}

// for range
str1 := "hello北京"
for i, v := range str1 {
	fmt.Printf("第 %v 个字符, 字符为 %c, ascii码值为 %v\n", i, v, v)
}

5.4.3 转整型

n,err := strconv.Atoi("12")  // 转换不成功会有err 返回值,可以通过对err进行判断

5.4.4 整型转字符串

str := strconv.Itoa(123)

5.4.5 字符串转 byte 数组

bytes := []byte("hello go")  // 转成字节

5.4.6 byte数组 转字符串:

 str := string([]byte{97,98,99})  // 转成97,98,99对应的字符组成字符串

5.4.7 查询子串是否在字符串中

b := strings.Contains("hello","o")  // 返回值为bool

5.4.8 统计指定子串个数

strings.Count("ceheese","e")    // 没有返回0

5.4.9 不区分大小写的字符串比较

==是区分大小写的比较

strings.EqualFold("ab","AB")   // 返回值为bool

5.4.10 返回子串在字符串中第一次出现的index值

如果没有返回-1

strings.index("abcaa","a")

5.4.11 字符串替换

strings.Replace("go go hello","go","go语言",n) // n可以指定替换几个,如果n=-1, 表示全部替换

5.4.12 大小写转换

strings.Tolower("Go") 
strings.ToUpper("go")

5.4.13 去除字符串两边的空格

strings.TrimSpace(" hello ")

5.4.14 字符串两边,指定字符去除

strings.Trim("!hello!","!")

5.4.15 字符串左边指定字符去除

strings.TrimLeft("!hello","!")

5.4.16 字符串右边指定字符去除

strings.TrimRight("!hello!","!")

5.4.17 是否以指定字符开头

strings.HasPrefix("http://","http")

5.4.18 是否以指定字符结束

strings.HasSuffix("http://www.baidu.com","com")

5.4.19 拼接字符串

+ 拼接

func main() {
	s1 := "小明"
	s2 := "啊"
	fmt.Println(s1 + s2)
}

// 打印结果
小明啊

fmt.Sprintf()

func main() {
	s1 := "小明"
	s2 := "啊"
	fmt.Println(fmt.Sprintf("%v%v",s1,s2))
}

// 打印结果
小明啊

5.4.20 分割

func main() {
	var s1 string = "小明a啊"
	fmt.Println(strings.Split(s1,"a"))
}


// 打印结果
[小明 啊]

5.4.21 索引取值

func main() {
	var s1 string = "小明a啊a"
    fmt.Println(s1[0])
	fmt.Println(s1[0:3])
}

// 打印结果
229
小

5.4.22 join

func main() {
	var a  = []string{"a","b","c"}
	fmt.Println(strings.Join(a,"_"))
}

// 打印结果
a_b_c

5.4.23 修改子串

要修改字符串,需要先将其转换成[]rune或[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。

func main() {
	// 转成 []rune
	s1 := "小明啊"
	rs1 := []rune(s1)
	rs1[0] = '又'
	s1 = string(rs1)
	fmt.Println(s1)

	// 转成 []byte
	s2 := "Hello"
	rs2 := []byte(s2)
	rs2[0] = 'J'
	s2 = string(rs2)
	fmt.Println(s2)
}


// 打印结果
又明啊
Jello

5.5 注意事项

  1. Go语言的字符串的字节使用UTF-8编码表示Unicode文本,乱码问题不会再成为困扰

  2. 字符串一旦赋值,字符串就不能修改了,在Go中字符串是不可变的

    var address string = "背景你好"
    // address[0] = "我不好"  // 不可改变字符串中的某个元素 
    address = "我不好"    // 可以重新赋值
    fmt.Println(address,unsafe.Sizeof(address))
    
  3. 字符串的表示方法有两种

    1. 双引号,会识别\这种转义字符
    2. 反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防止共计,或者输出源代码等效果
  4. 字符串拼接方式

    var address string = "北京你好"
    var age string = "18"
    
    var address_age = address + age
    fmt.Println(address_age)
    
    address += age
    fmt.Println(address)
    
  5. 当字符串的长度太长是,需要使用到多行字符串,注意需要将+保留在上一行,因为编译器会自动加分号
    不保留在上一行,会表示这一行代码结束了,下一行代码就会有错

    var address string = "背景你好" +
    	"今天"
    // var address string = "背景你好"    
    // + "今天"      // 错误!!! + 号要留在上一行
    fmt.Println(address)
    

6. 基本数据类型的默认值

在Go中,数据类型都有一个默认值,当没有赋值时,就会保留其默认值,在Go中的默认值又叫做零值

7. 基本数据类型的转换

Go在不同类型的变量之间赋值时需要显示转换(强制转换),也就是说golang中数据类型不能自动转换

1. 语法格式

T(v)

// 将值v转换为类型T
	// T:就是数据类型,比如int32,int64,float32等等
	// v:就是需要转换的变量

1. int 和 float 的 转换

func main(){
    // int转成int32
	var str_num int = 1
	int_num := int32(str_num)

	// float64转成float32
	var float_num = 3.125
	var new_float_num float32 = float32(float_num)

	// int转成float64
	var str_num int = 1
	int_num := float64(str_num)
}

2. string的转换

在程序开发中,经常需要将基本数据类型转换成string类型,或者将string类型转成基本数据类型

2.1 fmt.Sprint

func main() {
	var str1_num int = 1000
	var str string // 空的字符串
    str = fmt.Sprintf("%d", str1_num)  //字符串拼接
	fmt.Printf("str1_num 转换后的 type (%T) is %q\n", str, str)
}

2.2 strconv包的函数

// 将整型转成任意进制的字符串
strconv.FormatInt(int64(str1_num),2)

// 将整型转成十进制的字符串
// 底层调用FormatInt(str_num,10)
strconv.Itoa(str_num)


package main

import (
	"fmt"
	"strconv"
)

func main() {

	var str1_num int = 1000
	var str2_num float64 = 154.24554
	var str3_num bool = true
    var str4_num int = 123
    var str4_num int64 = 456
	
	var str string // 空的字符串
	// 参数1类型为int64,参数2表示进制
	str = strconv.FormatInt(int64(str1_num),2)
	fmt.Printf("str1_num(%T) 转换后为 %q\n",str,str)

	str = strconv.FormatFloat(str2_num,'f',10,64)  // float转成10位的float64的字符串
	fmt.Printf("str1_num(%T) 转换后为 %q\n",str,str)

	str = strconv.FormatBool(str3_num)  // bool 转成 字符串
	fmt.Printf("str1_num(%T) 转换后为 %q\n",str,str)

    str = strconv.Itoa(str4_num)  // int类型很方便的转换成字符串
	fmt.Printf("str (%T) 转换后为%q",str,str)

    str = strconv.Itoa(int(str5_num))  // int64必须转成int,才可以用这个函数
	fmt.Printf("str (%T) 转换后为%q",str,str)

}

2.3 string转成基本数据类型

package main

import (
	"fmt"
	"strconv"
)

func main() {

	var str1 string = "true"
	var str_to_bool bool
	str_to_bool , _ = strconv.ParseBool(str1)
	fmt.Printf("str_to_bool (%T) 转换成%q\n",str_to_bool,str_to_bool)

	var str2 string = "123456"
	var str_to_int int64
	var str_to_int2 int
	str_to_int , _ = strconv.ParseInt(str2,10,64) // 只能转成int64,如果是int需要强转
	str_to_int2 = int(str_to_int)
	fmt.Printf("str_to_bool (%T) 转换成%v\n",str_to_int2,str_to_int2)

	var str3 string = "12.1254"
	var str_to_float float64

	str_to_float , _ = strconv.ParseFloat(str3,64)
	fmt.Printf("str_to_float (%T) 转换成%v",str_to_float,str_to_float)

}

说明: 因为返回的是int64或者float64,如果希望得到int32或float32,用int32()/float32()强转一下

3. 注意事项

  1. Go中,数据类型的转换可以是表示范围小转为表示范围大,表示范围大转为表示范围小

  2. 转换过程为重新开辟空间并定义类型,不会改变原来的变量的类型

  3. 在转换中,比如将int64转成int8,编译时不会报错,只是转换的结果是按溢出处理(得到一个和希望结果不一样的值)

    var n1 int32 = 12
    n4 := int8(n1) + 127
    fmt.Println(n4)  // 结果为-117
    
  4. 不同的数据类型运算时需要强制转换后再运算

    var a int32 = 10
    var b int64 = 32
    
    // 不同的数据类型运算时,要强制转换后再运算
    fmt.Println(int64(a) + b)
    
  5. 在将string类型转换成基本数据类型时,要确保string类型能够转成有效的数据,比如可以吧"123"转成一个整数,但是不能把"hello" 转成一个整数,如果这样做,Golang 直接将其转换成0,其他所有转不成功的数据类型都会置其为默认值

posted @ 2021-08-24 15:06  河图s  阅读(903)  评论(0)    收藏  举报