数据类型
程序中+号的使用
当左右两边都是数值型时,则做加法运算
当左右两边都是字符串,则做字符串拼接
一、数据类型的基本介绍
每一种数据都定义了明确的数据类型,在内存中分配了不同大小的内存空间。
1、基本数据类型
数值型:
(1)、整数类型(int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、byte)
(2)、浮点类型(float32、float64)
字符型(没有专门的字符型,使用byte来保存单个字母字符)
布尔型(bool)
字符串(string)[官方将string归属基本数据了型]
2、派生/复杂数据类型
指针(pointer)、数组、结构体(struct)、管道(channel)、函数、切片(slice)、接口(interface)、map
二、整数类型
整数就是用来存放整数值的。
类型 | 有无符号 | 占用存储空间 | 表示范围 |
int8 | 有 | 1字节 | -128 ~ 127 |
int16 | 有 | 2字节 | -215 ~ 215 -1 |
int32 | 有 | 4字节 | -231 ~ 231 -1 |
int64 | 有 | 8字节 | -263 ~ 263 -1 |
uint8 | 无 | 1字节 | 0 ~ 255 |
uint16 | 无 | 2字节 | 0 ~ 216 -1 |
uint32 | 无 | 4字节 | 0 ~ 232 -1 |
uint64 | 无 | 8字节 | 0 ~ 264 -1 |
int的其他类型
类型 | 有无符号 | 占用存储空间 | 表示范围 | 备注 |
int | 有 |
32位系统占4个字节 64位系统占8个字节 |
-231 ~ 231 -1 -263 ~ 263 -1 |
|
uint | 无 |
32位系统占4个字节 64位系统占8个字节 |
0 ~ 232 -1 0 ~ 264 -1 |
|
rune | 有 | 同int32 | -231 ~ 231 -1 | 等价int32,表示一个unicode码 |
byte | 无 | 同uint8 | 0 ~ 255 | 当要存储字符时选用byte |
golang整型默认声明为int型
查看某个变量的字节大小和数据类型
package main import ( "fmt" "unsafe" ) //在程序中查看某个变量的占用字节大小和数据类型 func main(){ var n int=10 //unsafe.Sizeof(n)是unsafe包的一个函数,可以返回n变量占用的字节数 fmt.Printf("n的数据类型是 %T , 占用的字节数是 %d",n,unsafe.Sizeof(n)) }
golang程序中整型变量在使用时,遵守保小不保大的原则,即在保证程序正确运行下,尽量使用占用空间小的数据类型。
三、浮点类型
浮点型就是用于存放小数的。
类型 | 占用存储空间 | 表示范围 |
单精度float32 | 4字节 | -3.403E38 ~ 3.403E38 |
双精度float64 | 8字节 | -1.798E308 ~ 1.798E308 |
浮点数都是有符号的,浮点数=符号位+指数位+尾数位
float64的精度比float32的要准确。
golang的浮点型默认声明为float64。
浮点型常量有两种表示形式:十进制数形式和科学计数法形式。
四、字符类型
golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。
字符串就是一串固定长度的字符连接起来的字符序列。go的字符串是由单个字节连接起来的。也就是说对于传统的字符串是由字符组成的,而go的字符串不同,它是由字节组成的。
package main import "fmt" func main() { var c1 byte = 'a' var c2 byte = '0' //字符0 //当直接输出byte值时就是输出对应当字符当码zhi fmt.Println("c1=", c1) fmt.Println("c2=", c2) //如果希望输出byte值对应的字符,需要使用格式化输出 fmt.Printf("c1=%c,c2=%c\n", c1, c2) //var c3 byte = '北' //overflows溢出 var c3 int = '北' fmt.Printf("c3=%c c3对应码值=%d", c3, c3) }
如果保存的字符在ASCII表的,比如[0-1, a-z,A-Z..]直接可以保存到byte
如果保存的字符对应码值大于255,这时可以考虑使用int类型保存
如果需要按照字符的方式输出,这时需要格式化输出,即fmt.Printf(“%c”, c)
字符类型使用细节:
1、字符常量是用单引号('')括起来的单个字符。例如:var c1 byte = 'a' var c2 int = '中' var c3 byte = '9'
2、go中允许使用转义字符'\’来将其后的字符转变为特殊字符型常量。例如:var c3 char = ‘\n’ // '\n'表示换行符
3、go语言的字符使用UTF-8编码。英文字母-1个字节 汉字-3个字节
4、在go中,字符的本质是一个整数,直接输出时,是该字符对应的UTF-8编码的码值
5、可以直接给某个变量赋一个数字,然后按格式化输出时%c,会输出该数字对应的unicode字符
6、字符类型是可以进行运算的,相当于一个整数,因为它都对应有unicode码
package main import "fmt" func main() { //可以直接给某个变量赋一个数字,然后按格式化输出时%c,会输出该数字对应的unicode字符 var c int = 22269 //22269 -> '国' fmt.Printf("c=%c\n", c) //字符类型是可以进行运算的,相当于一个整数,因为它都对应有unicode码 var n = 10 + 'a' //10+97=107 fmt.Println("n=", n) }
字符型存储到计算机中,需要将字符对应的码值(整数)找出来。
存储:字符 --> 对应码值 --> 二进制 --> 存储
读取:二进制 --> 码值 --> 字符 --> 读取
符和码值的对应关系是通过字符编码表决定的。
go语言的编码都统一成了utf-8。非常的方便,很统一,再也没有编码乱码的困扰了。
五、布尔类型
布尔类型bool只允许取值true和false。
bool类型占1个字节。
bool类型适用于逻辑运算,一般用于程序流程控制。
package main import ( "fmt" "unsafe" ) func main() { //bool类型只能取true和false var b bool=false //bool类型占用存储空间是1个字节 fmt.Printf("b的占用空间 = %d 字节",unsafe.Sizeof(b)) }
六、string类型
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。
1、Go语言的字符串的字节使用UTF-8编码标识Unicode文本,这样Golang统一使用UTF-8编码,中文 乱码问题不会再困扰程序员。
2、字符串一旦赋值了,字符串就不能修改了:在Go中字符串是不可变的。
3、符串的两种表示形式
(1)双引号, 会识别转义字符
(2)反引号(``),以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果
4、字符串拼接方式用+号
5、当一行字符串太长时,需要使用到多行字符串,需要将+号保留到上一行。
七、基本数据类型的默认值
在go中,数据类型都有一个默认值,当程序员没有赋值时,就会保留默认值,在go中,默认值又叫零值。
数据类型 | 默认值 |
整型 | 0 |
浮点型 | 0 |
字符型 | "" |
布尔类型 | false |
八、基本数据类型的相互转换
1、基本介绍
Golang和java/c不同,Go在不同类型的变量之间赋值时需要显式转换。也就是说Golang中数据类型不能自动转换。
2、基本语法
表达式T(v)将值v转换为类型T
T就是数据类型,比如int32,int64,float32等等
v就是需要转换的变量
package main import "fmt" func main() { var i int32 = 100 var n1 float32 = float32(i) var n2 int8 = int8(i) //低精度 -> 高精度 var n3 int64 = int64(i) fmt.Println("i=%v n1=%v n2=%v n3=%v", i, n1, n2, n3) }
3、注意事项
(1)、Go中,数据类型的转换可以是从表示范围小 -> 表示范围大,也可以范围大 --> 范围小
(2)、被转换的是变量存储的数据(即值),变量本身的数据类型并没有变化!
(3)、在转换中,比如将int64转成int8[-128---127],编译时不会报错,只是转换的结果是按溢出处理,和希望的结果不一样。 因此在转换时,需要考虑范围。
package main import "fmt" func main() { var i int32 = 100 var n1 float32 = float32(i) var n2 int8 = int8(i) //低精度 -> 高精度 var n3 int64 = int64(i) fmt.Println("i=%v n1=%v n2=%v n3=%v", i, n1, n2, n3) //被转换的是变量存储的数据(即值),变量本身的数据类型并没有变化 fmt.Printf("i type is %T\n", i) }
4、基本数据类型和 string 的转换
在程序开发中,经常将基本数据类型转成string,或者将string转成基本数据类型。
(1)、基本类型转string类型
- 方式1:fmt.Sprintf("%参数", 表达式)
func Sprintf(format string, a ...interface{}) string
Sprintf根据format参数生成格式化的字符串并返回该字符串。
package main import "fmt" func main() { var num1 int = 99 var num2 float64 = 23.456 var b bool = true var myChar byte = 'h' var str string //空的string str = fmt.Sprintf("%d", num1) fmt.Printf("str type %T str = %q\n", str, str) str = fmt.Sprintf("%f", num2) fmt.Printf("str type %T str = %q\n", str, str) str = fmt.Sprintf("%t", b) fmt.Printf("str type %T str = %q\n", str, str) str = fmt.Sprintf("%c", myChar) fmt.Printf("str type %T str = %q\n", str, str) }
- 方式2:使用strconv包的函数
func FormatBool(b bool) string
根据b的值返回"true"或"false"。
func FormatInt(i int64, base int) string
返回i的base进制的字符串表示。base 必须在2到36之间,结果中会使用小写字母'a'到'z'表示大于10的数字。
func FormatUint(i uint64, base int) string
是FormatInt的无符号整数版本。
func FormatFloat(f float64, fmt byte, prec, bitSize int) string
函数将浮点数表示为字符串并返回。
bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。
fmt表示格式:'f'(-ddd.dddd)、'b'(-ddddp±ddd,指数为二进制)、'e'(-d.dddde±dd,十进制指数)、'E'(-d.ddddE±dd,十进制指数)、'g'(指数很大时用'e'格式,否则'f'格式)、'G'(指数很大时用'E'格式,否则'f'格式)。
prec控制精度(排除指数部分):对'f'、'e'、'E',它表示小数点后的数字个数;对'g'、'G',它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。
func Itoa(i int) string
Itoa是FormatInt(i, 10) 的简写。
package main import ( "fmt" "strconv" ) func main() { var num3 int = 99 var num4 float64 = 23.456 var num5 int64 = 45678 var b bool = true var str string str = strconv.FormatInt(int64(num3), 10) fmt.Printf("str type %T str = %q\n", str, str) str = strconv.FormatFloat(num4, 'f', 10, 64) fmt.Printf("str type %T str = %q\n", str, str) str = strconv.FormatBool(b) fmt.Printf("str type %T str = %q\n", str, str) str = strconv.Itoa(int(num5)) fmt.Printf("str type %T str = %q\n", str, str) }
(2)、string 类型转基本数据类型
func ParseBool(str string) (value bool, err error)
返回字符串表示的bool值。它接受1、0、t、f、T、F、true、false、True、False、TRUE、FALSE;否则返回错误。
func ParseInt(s string, base int, bitSize int) (i int64, err error)
返回字符串表示的整数值,接受正负号。
base指定进制(2到36),如果base为0,则会从字符串前置判断,"0x"是16进制,"0"是8进制,否则是10进制;
bitSize指定结果必须能无溢出赋值的整数类型,0、8、16、32、64 分别代表 int、int8、int16、int32、int64;返回的err是*NumErr类型的,如果语法有误,err.Error = ErrSyntax;如果结果超出类型范围err.Error = ErrRange。
func ParseUint(s string, base int, bitSize int) (n uint64, err error)
ParseUint类似ParseInt但不接受正负号,用于无符号整型。
func ParseFloat
func ParseFloat(s string, bitSize int) (f float64, err error)
解析一个表示浮点数的字符串并返回其值。
如果s合乎语法规则,函数会返回最为接近s表示值的一个浮点数(使用IEEE754规范舍入)。bitSize指定了期望的接收类型,32是float32(返回值可以不改变精确值的赋值给float32),64是float64;返回值err是*NumErr类型的,语法有误的,err.Error=ErrSyntax;结果超出表示范围的,返回值f为±Inf,err.Error= ErrRange。
package main import ( "fmt" "strconv" ) func main() { var str string = "true" var b bool //strconv.ParseBool(str)函数返回两个值(value bool,err error) //若只获取一个value bool,不获取err,则可使用 _ 忽略 b, _ = strconv.ParseBool(str) fmt.Printf("b type %T b = %v\n", b, b) var str2 string = "1234590" var n1 int64 var n2 int n1, _ = strconv.ParseInt(str2, 10, 64) n2 = int(n1) fmt.Printf("n1 type %T n1 = %v\n", n1, n1) fmt.Printf("n2 type %T n2 = %v\n", n2, n2) var str3 string = "123.456" var f1 float64 f1, _ = strconv.ParseFloat(str3, 64) fmt.Printf("f1 type %T f1 = %v\n", f1, f1) }
string 转基本数据类型的注意事项
在将string类型转成 基本数据类型时,要确保string类型能够转成有效的数据,比如可以 把 "123" , 转成一个整数,但是不能把 "hello" 转成一个整数,如果这样做,Golang 直接将其转成 0 , 其它类型也是一样的道理. float --> 0 bool --> false
package main import ( "fmt" "strconv" ) func main() { var str string = "hello" var n int64 = 11 n, _ = strconv.ParseInt(str, 10, 64) fmt.Printf("n type %T n = %v\n", n, n) }
九、指针
1、基本介绍
(1)、基本数据类型,变量存的就是值,也叫值类型
(2)、获取变量的地址,用&,比如:var num int, 获取num的地址:&num
基本数据类型在内存的布局如下图:
(3)、指针类型,指针变量存的是一个地址,这个地址指向的空间存的才是值 比如:var ptr *int = &num
指针在内存的布局如下图:
(4)、获取指针类型所指向的值,使用:*,比如:var ptr *int, 使用*ptr 获取 ptr 指向的值
package main import "fmt" func main() { var i int = 10 fmt.Println("i的地址 = ", &i) //ptr是一种指针变量,ptr的类型是*int,ptr本身的值&i var ptr *int = &i fmt.Printf("ptr = %v\n", ptr) fmt.Printf("ptr 的地址 = %v\n", &ptr) fmt.Printf("ptr 指向的值 = %v\n", *ptr) }
2、指针练习题
写一个程序,获取一个int变量num的地址,并显示到终端;将num的地址赋给指针ptr , 并通过ptr去修改num的值。
package main import "fmt" func main() { var num int = 9 fmt.Printf("num address = %v\n", &num) var ptr *int ptr = &num *ptr = 10 fmt.Printf("num = %v", num) }
3、指针的使用细节
(1)、值类型,都有对应的指针类型, 形式为*数据类型,比如int的对应的指针就是 *int, float32对应的指针类型就是 *float32, 依次类推。
(2)、值类型包括:基本数据类型int系列, float系列, bool, string 、数组和结构体struct。
十、值类型和引用类型
值类型:基本数据类型int系列, float系列, bool, string 、数组和结构体struct
引用类型:指针、切片slice、map、管道channel、接口interface等都是引用类型
值类型:变量直接存储值,内存通常在栈中分配
引用类型:变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆 上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收。
十一、标识符的命名规范
Golang 对各种变量、方法、函数等命名时使用的字符序列称为标识符
凡是自己可以起名字的地方都叫标识符
1、标识符的命名规则:
(1)、由26个英文字母大小写,0-9 ,_ 组成
(2)、数字不可以开头。var num int //ok var 3num int //error
(3)、Golang中严格区分大小写。
var num int
var Num int
说明:在 golang 中,num和Num是两个不同的变量
(4)、标识符不能包含空格
(5)、下划线"_"本身在 Go 中是一个特殊的标识符,称为空标识符。可以代表任何其它的标识符,但 是它对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能作为标识符使用
(6)、不能以系统保留关键字作为标识符(一共有 25 个),比如 break,if 等等
2、标识符命名注意事项:
(1)、包名:保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,不要和标准库冲突。
(2)、变量名、函数名、常量名:采用驼峰法。
(3)、如果变量名、函数名、常量名首字母大写,则可以被其他的包访问;如果首字母小写,则只能在本包中使用 ( 注:可以简单的理解成,首字母大写是公开的,首字母小写是私有的) ,在 golang 没有 public , private 等关键字。
十二、系统的保留关键字和预定义标识符
1、系统保留关键字
在golang中,为了简化代码编译过程中对代码的解析,其定义的保留关键字只有25个。
break | default | func | interface | select |
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
2、预定义标识符
除了保留关键字外,golang还提供六36个预定义的标识符,其包括基础数据类型和系统内嵌函数
append | bool | byte | cap | close | complex |
complex64 | complex128 | uint16 | copy | false | float32 |
float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new |
nil | panic | uint64 | println | real | |
recover | string | true | uint | uint8 | uintprt |