第三章:Go语言基础数据类型

golang-gopher.png

1. Go语言数据类型

1.1 数据类型分类

Go语言数据类型大致可以分为两类

  1. 基础类型,其中就包括了我们最常见的一些类型

    类型 名称 长度 零值 说明
    bool 布尔类型 1 false 其值不为真即为家,不可以用数字代表true或false
    byte 字节型 1 0 uint8别名
    rune 字符类型 4 0 专用于存储unicode编码,等价于uint32
    int, uint 整型 4或8 0 32位或64位
    int8, uint8 整型 1 0 -128 ~ 127, 0 ~ 255
    int16, uint16 整型 2 0 -32768 ~ 32767, 0 ~ 65535
    int32, uint32 整型 4 0 -21亿 ~ 21 亿, 0 ~ 42 亿
    int64, uint64 整型 8 0
    float32 浮点型 4 0.0 小数位精确到7位
    float64 浮点型 8 0.0 小数位精确到15位
    complex64 复数类型 8
    complex128 复数类型 16
    uintptr 整型 4或8 ⾜以存储指针的uint32或uint64整数
    string 字符串 "" utf-8字符串
  2. 复合类型, 这些类型构成了Go语言的特点

    1. 指针 (pointer)
    2. 数字 (array)
    3. 切片 (slice)
    4. 字典(map)
    5. 通道 (chan)
    6. 结构体 (struct)
    7. 接口 (interface)

2. 布尔类型

  1. 也叫做bool类型
  2. bool 类型数据的值只能是true 或者 false
  3. bool 类型默认值是false
  4. bool 类型 占1个字节
  5. bool类型一般用于流程控制
  6. bool类型不能接受其他类型赋值
  7. bool类型不支持自动或者强制类型装换
package main

import "fmt"

var a bool

func main() {
    //a = 1 // 错误 cannot use 1 (type int) as type bool in assignment
    fmt.Printf("type = %T\n", a)
    fmt.Printf("value = %v\n", a)
    if a {
        fmt.Println("this is true")
    } else {
        fmt.Println("this is false")
    }
}
type = bool
value = false
this is false

3. 整数类型

  1. 整数类型就是存放整数值得

  2. int类型和uint类型自动匹配平台长度

    类型 有无符号 占用空间 范围 备注
    int 32位系统4个字节<br />64位系统8个字节 -2^31~2^31-1<br />-2^63~2^63-1
    uint 32位系统4个字节<br />64位系统8个字节 0~2^32-1<br />0~2^64-1
    rune 与int32一样 -2^31~2^31-1 等价int32,表示一个Unicode码
    byte 与uint8等价 0~255 存储字符使用
  3. Go语言的整型默认声明是int型

  4. 通常int和int32被认为是两种不同的类型,编译器不会做自动装换

  5. 整数类型可以进行数值运算 (加减乘除和求余)

  6. 整数类型可以进行比较运算(> , < ,==, >= , <= ,!=)

  7. 两个不同类型的整数不能比较,即使他们的值看着相同也不行

3.1 查询某个变量的字节大小和数据类型

package main

import (
    "fmt"
    "unsafe"
)

var v1 int8
var v2 int16 = 88
var v3 int32 = 8978923
var v4 = 8978989
var v5 int64
var v6 rune
func main(){
    fmt.Printf("v1 类型是%T, v1 占的字节数是%d\n",v1,unsafe.Sizeof(v1))
    fmt.Printf("v2 类型是%T, v2 占的字节数是%d\n",v2,unsafe.Sizeof(v2))
    fmt.Printf("v3 类型是%T, v3 占的字节数是%d\n",v3,unsafe.Sizeof(v3))
    fmt.Printf("v4 类型是%T, v4 占的字节数是%d\n",v4,unsafe.Sizeof(v4))
    fmt.Printf("v5 类型是%T, v5 占的字节数是%d\n",v5,unsafe.Sizeof(v5))
    fmt.Printf("v6 类型是%T, v6 占的字节数是%d\n",v6,unsafe.Sizeof(v6))
}
v1 类型是int8, v1 占的字节数是1
v2 类型是int16, v2 占的字节数是2
v3 类型是int32, v3 占的字节数是4
v4 类型是int, v4 占的字节数是8
v5 类型是int64, v5 占的字节数是8
v6 类型是int32, v6 占的字节数是4

3.2 如何证明int和int64不是同一种类型

package main

import (
    "fmt"
    "unsafe"
)

var v1 = 99
var v2 int64
func main(){
    fmt.Printf("v1的类型是%T,v1占的字节长度是%d\n",v1,unsafe.Sizeof(v1))
    fmt.Printf("v2的类型是%T,v2占的字节长度是%d\n",v2,unsafe.Sizeof(v2))
    // 将v1的值赋给v2
    //v2 = v1  // 错误 cannot use v1 (type int) as type int64 in assignment
    v2 = int64(v1) // 通过
    fmt.Printf("v2的值是%v,v2的类型是%T",v2,v2)
}

v1的类型是int,v1占的字节长度是8
v2的类型是int64,v2占的字节长度是8
v2的值是99,v2的类型是int64

3.3 不同的整数类型不能比较

package main

import "fmt"

var a int32
var b int64
func main(){
    a,b=8,8
    if a == b{   //invalid operation: a == b (mismatched types int32 and int64)
        fmt.Println("===")
    }
}

4. 浮点型

浮点型用于表示包含小数点的数据,例如 1.234 , 0.99 , -9.9等就是一个浮点型数据,Go语言中的浮点型采用 IEEE-754 标准的表达方式

Go语言定义两个浮点类型float32和float64,其中float32相当于C语言中的float类型, float64等价于C语言中的double类型

类型 占用存储空间 范围
单精度float32 4字节 -3.4028234663852886e+38~3.4028234663852886e+38
双精度float64 8字节 -1.7976931348623157e+308~1.7976931348623157e+308

4.1 浮点数 = 符号位+指数位+尾数位

4.2 浮点数都是有符号的

package main

import "fmt"

func main(){
    var p float32 = 99.99
    fmt.Println(p)
    var p1 float32 = -0.33
    fmt.Println(p1)
    var p2 float64 = -79787878.9
    fmt.Println(p2)

}
99.99
-0.33
-7.97878789e+07

4.3 float64 比float32准确

小数部分可能丢失,造成精度损失,要保存高精度的数应该选择float64

Go语言的浮点型默认是float64类型

package main

import "fmt"

func main(){
    var p1 float32  = 897.0000023
    var p2 float64  = 897.0000023
    fmt.Println("p1 = ",p1)
    fmt.Println("p2 = ",p2)
    p3 := -12.90
    // GO语言默认是使用float64类型
    fmt.Printf("p3 type = %T",p3)
}
p1 =  897
p2 =  897.0000023
p3 type = float64

4.4 浮点是强制转换

需要说明float32 和 float64 是两种类型,不能直接相互赋值

package main

import "fmt"

var f1 float32
var f2 float64
func main() {
    f2 = 1212.09
    fmt.Printf("f2 type  is %T, value is %v\n",f2,f2)
    // 运行报错
    //cannot use f2 (type float64) as type float32 in assignment
    f1 = f2
    fmt.Printf("f1 type  is %T, value is %v\n",f1,f1)
}

我们看看浮点数float32 和 float64类型怎么转换

package main

import "fmt"

var f1 float32
var f2 float64
func main() {
    f2 = 1212.09
    fmt.Printf("f2 type  is %T, value is %v\n",f2,f2)
    // 强制转换成float32类型
    f1 = float32(f2)
    fmt.Printf("f1 type  is %T, value is %v\n",f1,f1)

}
f2 type  is float64, value is 1212.09
f1 type  is float32, value is 1212.09

5. 字符类型

Go语言中支持两种字符类型 分别是byte 和 rune

  1. byte型 ,实际上是uint8类型的别称,代表了ASCII码的一个字符

  2. rune 类型,代表一个unicode 字符 ,实际是一个int32类型,在处理中文,日文或者其他符合类型时需要用到,Go语言中使用特殊的rune类型来处理Unicode,让基于Unicode的文本处理更为方便

    package main
    
    import "fmt"
    
    func main() {
       var a byte = 'a'
       var b rune = '中'
       // a的值`a`对应的ASCII编码是97 实际类型是uint8
       fmt.Printf("a value = %d type = %T\n", a, a)
       // b的值`中`对应的Unicode码是20013 实际类型是int32
       fmt.Printf("b value = %d type = %T\n", b, b)
       // 输出对应的字符
       fmt.Printf("a = %c b = %c",a,b)
    }
    
    a value = 97 type = uint8
    b value = 20013 type = int32
    a = a b = 中
    

Unicode 是字符集,ASCII 也是一种字符集,UTF-8是一种编码规则

字符集为每一个字符分配一个唯一的ID,我们使用的所有字符在unicode字符集中都有唯一的ID对应.

utf-8 是编码规则,将unicode字符集中的ID以某种形式进行编码

在Go语言中,字符的本质是一个数字,格式化输出时%c,会输出该数字对应的unicode字符

package main

import "fmt"

func main(){
  var v1 int8 = 102
  fmt.Printf("v1 = %c\n",v1)
  var v2 int = 22381
  fmt.Printf("v2 = %c\n",v2)
}
v1 = f
v2 = 坭

字符串是可以进行运算的

package main

import "fmt"

func main() {
  var v1 int = 10
  v1 += 97
  fmt.Printf("v1 = %d,unicode = %c",v1,v1)
}

v1 = 107,unicode = k

6. string类型

Go语言字符串数据对应的字节数组,字符串的只读属性禁止了在程序中对底层字节数组的元素修改,字符串赋值只是赋值了数据地址和对应长度,而不会底层数据的赋值

字符串是一串固定长度的字符连接起来的字符序列,Go语言的字符串的字节使用utf-8编码标识的unicode文本

字符串类型也就是string类型定义很简单

package main

import "fmt"

var s1 string
func main() {
    s1 = "Celtic 凯尔特人"
    s2 := "Lakers 湖人"
    var s3 string = "Rocket 火箭"
    fmt.Printf("s1 = %s  type = %T\n",s1,s1)
    fmt.Printf("s2 = %s  type = %T\n",s2,s2)
    fmt.Printf("s3 = %s  type = %T\n",s3,s3)

}
s1 = Celtic 凯尔特人  type = string
s2 = Lakers 湖人  type = string
s3 = Rocket 火箭  type = string

字符串的内容可以用类似数组下标的方式获取,但是与数组不同的是,字符串的内容不能在初始化之后修改

package main

import "fmt"

func main() {
    var s1 string = "hello world ~~"
    // 使用内置函数len()获取字符串长度
    l := len(s1)
    fmt.Printf("s1 的长度是 : %d\n",l)
    // 获取第一个字符
    ch1 := s1[8]
    fmt.Printf("%c ch1 = %v,type = %T\n",ch1,ch1,ch1)

}

s1 的长度是 : 14
r ch1 = 114,type = uint8

看一个错误的例子

package main

import "fmt"

func main() {
    var s1 string = "hello world ~~"
    //会报编译错误
    s1[0] = "H"
    fmt.Println(s1[0])
}

cannot assign to s1[0]

字符串的两种表示形式

  1. 双引号 ,字符串的值在书写在双引号中是最常见的表达方式,也称为字符串字面量,这种形式不能跨行,如果字符串太长,可以使用 + 拼接
  2. 反引号, 以字符串原生样式输出,包括换行和特殊字符
package main

import "fmt"

func main() {
    s0 := "hello" +
        "world"
    s0 += "\n 中国"
    fmt.Println(s0)
}
helloworld
 中国
package main

import "fmt"

func main() {
    // 定义多行字符串
    var s1 string = `怒发冲冠
凭栏处潇潇雨歇
抬望眼
仰天长啸`
    fmt.Println(s1)
}

怒发冲冠
凭栏处潇潇雨歇
抬望眼
仰天长啸

以字节数组方式遍历数组

package main

import "fmt"

func main(){
    var s1 string  = "golang 中国"
    // 因为字符占1个字节,汉字占3个字节 所以参数s1的长度是13
    l := len(s1)
    for i:= 0 ;i<l;i++{
        ch := s1[i]  // 依据下标取字符串中的字符,类型为byte
        fmt.Printf("%T,%d,%d\n",ch,i,ch)
    }
}

uint8,0,103
uint8,1,111
uint8,2,108
uint8,3,97
uint8,4,110
uint8,5,103
uint8,6,32
uint8,7,228
uint8,8,184
uint8,9,173
uint8,10,229
uint8,11,155
uint8,12,189

以unicode字符遍历数组

package main

import "fmt"

func main(){
    var s1 string  = "golang 中国"
    for i,v := range  s1{
        // v是rune类型
        fmt.Printf("%d,%T,%d,%c\n",i,v,v,v)
    }
}

0,int32,103,g
1,int32,111,o
2,int32,108,l
3,int32,97,a
4,int32,110,n
5,int32,103,g
6,int32,32, 
7,int32,20013,中
10,int32,22269,国

6.1 补充1:基本数据类型转换

Go语言中不同类型变量之间相互赋值时需要显式转换(不能自动转换)

转换的表达式 T(v) , 意思是将v转换成T类型

多见于整数的不同类型之间的转换,或者不同浮点数类型之间的转换,或是整数与浮点数之间的相互转

package main

import "fmt"

func main() {
    var v1 int8 = 99
    var v2 int

    fmt.Printf("v1 type is %T,value is %d\n",v1,v1)
    fmt.Printf("v2 type is %T,value is %d\n",v2,v2)
    v2 = int(v1)
    fmt.Printf("v2 type is %T,value is %d\n",v2,v2)
}

v1 type is int8,value is 99
v2 type is int,value is 0
v2 type is int,value is 99

GO语言中数据类型的值范围可以从大向小转换,也可以从小向大转换

package main

import "fmt"

func main() {
    // int8 的范围是 -128 ~ 127
    var v1 int8
    var v2 int64 = 9999999
    var v3 float64
    // 不会报错, 结果是按溢出处理
    v1 = int8(v2)
    v3 = float64(v2)
    fmt.Printf("%T, %d\n",v1,v1)
    fmt.Printf("%T, %f\n",v3,v3)
}

int8, 127
float64, 9999999.000000

6.2 补充2 基本数据类型和string 类型的转换

在实际应用中,string 类型和基础类型的相互转换非常常见

例如,整数类和浮点数类型,bool型等与string类型之间的转换

基础类型转成string类型

方法1: 通过包 fmt 包的Sprintf()函数去实现

package main

import "fmt"

func main(){
    var v1 int64 = 99998767
    var f float64 = 90.7978
    var b bool = true
    var ch byte = 'w'
    var s string
    s = fmt.Sprintf("%d",v1)
    fmt.Printf("v2  = %s, %T\n",s,s)
    s = fmt.Sprintf("%f",f)
    fmt.Printf("v2  = %s, %T\n",s,s)
    s = fmt.Sprintf("%t",b)
    fmt.Printf("v2  = %s, %T\n",s,s)
    s = fmt.Sprintf("%c",ch)
    fmt.Printf("v2  = %s, %T\n",s,s)
}

v2  = 99998767, string
v2  = 90.797800, string
v2  = true, string
v2  = w, string

基础数据类型转换成string类型

方法2 : 使用 strconv 包中的函数实现

package main

import (
    "fmt"
    "strconv"
)

func main() {
    var n  int8  = 12
    var f float64 = 23.001
    var b bool  = false
    // FormatInt函数中传入的第一个参数应该是int64类型
    s := strconv.FormatInt(int64(n),10)
    fmt.Printf("s  = %s and type = %T\n",s,s)
    // 其中的参数说明参考文档
    s = strconv.FormatFloat(f,'f',10,64)
    fmt.Printf("s  = %s and type = %T\n",s,s)
    s = strconv.FormatBool(b)
    fmt.Printf("s  = %s and type = %T\n",s,s)
}

s  = 12 and type = string
s  = 23.0010000000 and type = string
s  = false and type = string

strconv 包中有其他的方法可以将string类型转换成整数类型,浮点数类型,bool类型,函数名为 ParseInt() ParseBool() ParseFloat() **ParseUint()

package main

import (
    "fmt"
    "strconv"
)

func main() {
    var s1 string = "99090"
    var s2 string = "12.090"
    var s3 string = "true"
    var s4 string = "97"
    var s5 string = "helloworld"
    n, _ := strconv.ParseInt(s1, 10, 64)
    fmt.Printf("n = %d,type = %T\n", n, n)
    f, _ := strconv.ParseFloat(s2, 64)
    fmt.Printf("f = %f,type = %T\n", f, f)
    b, _ := strconv.ParseBool(s3)
    fmt.Printf("b = %t,type = %T\n", b, b)
    n2, _ := strconv.ParseUint(s4, 10, 64)
    fmt.Printf("n2 = %d,type = %T\n", n2, n2)
    // 错误原因是s5的有效数据不能转换成指定的类型
    n3, err := strconv.ParseInt(s5, 10, 64)
    if err !=nil{
        fmt.Println("error = ",err)
    }else{
        fmt.Printf("n = %d,type = %T\n", n3, n3)
    }
}


n = 99090,type = int64
f = 12.090000,type = float64
b = true,type = bool
n2 = 97,type = uint64
error =  strconv.ParseInt: parsing "helloworld": invalid syntax

7. 补充3 Go语言中常见转义符

转义符 含义
\r 回车符(返回行首)
\n 换行符
\t 制表符
\' 单引号
\" 双引号
\\ 反斜杠
package main

import "fmt"

func main() {
    var s1 string = "\"D:\\Go\\bin\\go.exe\""
    fmt.Println(s1)
}

"D:\Go\bin\go.exe"
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • 布尔类型 布尔类型用于表示真假,类型名为bool,只有两个值true和false,占用一个字节宽度,零值为fals...
    imsilence阅读 545评论 0 0
  • 第2章 顺序编程 2.1 变量 变量声明 变量声明的类型信息放在变量之后,放在数组的中括号之后,作返回值类型放在方...
    fjxCode阅读 419评论 0 1
  • 其实时间是最好的良药,分手后的伤心是难免的,也因为每个人情况不同,痛苦程度不同,走出来的难易不同,好起来的...
    小确幸_494e阅读 141评论 0 0
  • 一个人的口述史: 我是1949年来到台湾的,当时和许多流离失所的人一样在基隆港登岸,上了岸后眼前一片萧索,不知道今...
    培根卷金针菇阅读 224评论 0 0
  • B君:“这周末校庆。” X君突然转头:“这周末校庆?我生日校庆后一天哎,学校这专门为我庆生啊,太客气了!” W君:...
    咸鱼燃_阅读 179评论 0 0