Go从入门到放弃之数据类型

简介: Go从入门到放弃之数据类型

阅读目录

                  数据类型概述

回到顶部

Go 支持的数据类型

基本数据类型

1

2

3

4

5

6

7

布尔类型:bool

整型:int8、byte、int16、intuint、uintptr 等

浮点类型:float32、float64

复数类型:complex64、complex128

字符串:string

字符类型:rune

错误类型:error

复合类型  

1

2

3

4

5

6

7

指针(pointer)

数组(array)

切片(slice)

字典(map)

通道(chan)

结构体(struct

接口(interface

回到顶部

一、变量、作用域、常量和枚举

变量声明和命名规则

纯粹的变量声明,Go 语言引入了关键字 var,并且将类型信息放在变量名之后,此外,变量声明语句不需要使用分号作为结束符,比如我们要声明一个类型为 int 的变量 v1,示例如下:

1

var v1 int

声明多个的变量 

1

2

3

4

5

var (

    v1 int

    v2 string

    ......

变量在声明之后,系统会自动将变量值初始化为对应类型的零值  

注意事项:如果变量名包含多个单词,Go 语言变量命名规则遵循驼峰命名法,即首个单词小写,每个新单词的首字母大写,如 userName,但如果你的全局变量希望能够被外部包所使用,则需要将首个单词的首字母也大写

变量初始化

声明变量时想要同时对变量值进行初始化,可以通过以下这些方式:

1

2

3

var v1 int = 10   // 方式一,常规的初始化操作

var v2 = 10       // 方式二,此时变量类型会被编译器自动推导出来

v3 := 10          // 方式三,可以省略 var,编译器可以自动推导出v3的类型

变量赋值与多重赋值

1

i, j = j, i

匿名变量

匿名变量通过下划线 _ 来声明,任何赋予它的值都会被丢弃。

1

2

3

4

5

func GetName() (userName, nickName string) {

    return "nonfu""学院君"

}

 

_, nickName := GetName()

变量的作用域

1

如果一个变量在函数体外声明,则被认为是全局变量,可以在整个包甚至外部包(变量名以大写字母开头)使用,<br>不管你声明在哪个源文件里或在哪个源文件里调用该变量。在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,<br>函数的参数和返回值变量也是局部变量

回到顶部

二、常量

常量定义

通过 const 关键字定义常量时,可以指定常量类型,也可以省略(底层会自动推导),常见的常量定义方式如下:

1

2

3

4

5

6

7

8

const Pi float64 = 3.14159265358979323846

const zero = 0.0 // 无类型浮点常量

const (          // 通过一个 const 关键字定义多个常量,和 var 类似

    size int64 = 1024

    eof = -1  // 无类型整型常量

)

const u, v float32 = 0, 3  // u = 0.0, v = 3.0,常量的多重赋值

const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", 无类型整型和字符串常量

预定义常量

Go 语言预定义了这些常量:truefalseiota

前面两个熟悉其他语言的应该都很熟悉,是布尔类型的真假值,iota 比较特殊,可以被认为是一个可被编译器修改的常量,

在每一个 const 关键字出现时被重置为 0,然后在下一个 const 出现之前,每出现一次 iota,其所代表的数字会自动增 1

从以下的例子可以基本理解 iota 的用法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package main

 

const (    // iota 被重置为 0

    c0 = iota   // c0 = 0

    c1 = iota   // c1 = 1

    c2 = iota   // c2 = 2

)

 

const (

    u = iota * 2;  // u = 0

    v = iota * 2;  // v = 2

    w = iota * 2;  // w = 4

)

 

const x = iota;  // x = 0

const y = iota;  // y = 0

如果两个 const 的赋值语句的表达式是一样的,那么还可以省略后一个赋值表达式。因此,上面的前两个 const 语句可简写为:  

1

2

3

4

5

6

7

8

9

10

11

const (

    c0 = iota

    c1

    c2

)

 

const (

    u = iota * 2

    v

    w

)

枚举

枚举中包含了一系列相关的常量,比如下面关于一个星期中每天的定义。Go 语言并不支持其他语言用于表示枚举的 enum 关键字,而是通过在 const 后跟一对圆括号定义一组常量的方式来实现枚举。

下面是一个常规的 Go 语言枚举表示法,其中定义了一系列整型常量:

1

2

3

4

5

6

7

8

9

10

const (

    Sunday = iota

    Monday

    Tuesday

    Wednesday

    Thursday

    Friday

    Saturday

    numberOfDays

)

常量的作用域

和函数体外声明的变量一样,以大写字母开头的常量在包外可见,函数体内声明的常量只能在函数体内生效。  

回到顶部

三、布尔类型

Go 语言中的布尔类型与其他主流编程语言差不多,类型关键字为 bool,可赋值且只可以赋值为预定义常量 truefalse。示例代码如下:

1

2

3

var v1 bool

v1 = true

v2 := (1 == 2) // v2 也会被推导为 bool 类型

通过表达式计算得到的布尔类型结果可以赋值给 Go 布尔类型变量:

1

2

3

var bool

b = (1!=0) // 编译正确

fmt.Println("Result:", b) // 打印结果为Result: true

由于强类型的缘故,Go 语言在进行布尔值真假判断时,对值的类型有严格限制,以下这些值在进行布尔值判断的时候(使用非严格的 == 比较符)都会被认为是 false  

1

2

3

4

5

6

7

布尔值 FALSE 本身

整型值 0(零)

浮点型值 0.0(零)

空字符串,以及字符串 “0”

不包括任何元素的数组

特殊类型 NULL(包括尚未赋值的变量)

从空标记生成的 SimpleXML 对象

Go 语言中不同类型的值不能使用 ==!= 运算符进行比较  

回到顶部

四、整型

Go 语言默认支持如下这些整型类型:

类型 长度(单位:字节) 说明 值范围 默认值
int8 1 带符号8位整型 -128~127 0
uint8 1 无符号8位整型,与 byte 类型等价 0~255 0
int16 2 带符号16位整型 -32768~32767 0
uint16 2 无符号16位整型 0~65535 0
int32 4 带符号32位整型,与 rune 类型等价 -2147483648~2147483647 0
uint32 4 无符号32位整型 0~4294967295 0
int64 8 带符号64位整型 -9223372036854775808~9223372036854775807 0
uint64 8 无符号64位整型 0~18446744073709551615 0
int 32位或64位 与具体平台相关 与具体平台相关 0
uint 32位或64位 与具体平台相关 与具体平台相关 0
uintptr 与对应指针相同 无符号整型,足以存储指针值的未解释位 32位平台下为4字节,64位平台下为8字节 0

回到顶部

五、运算符

算术运算符

Go 语言支持所有常规的整数四则运算:+-*/%(取余运算只能用于整数)

运算符 描述
+ 相加
- 相减
* 相乘
/ 相除
% 求余

由于强类型的关系,在 Go 语言中,不同类型的整型值不能直接进行算术运算,比如下面这样计算就会报编译错误:

1

intValue3 := intValue1 + intValue2

类型转化之后就好了:

1

intValue3 := intValue1 + int8(intValue2)

在 Go 语言中,也支持自增/自减运算符,即 ++/--,但是只能作为语句,不能作为表达式,且只能用作后缀,不能放到变量前面 

1

2

3

intValue1++  // 有效,intValue1 的值变成 9

intValue1 = intValue1++ // 无效,编译报错

--intValue1  // 无效,编译报错

还支持 +=-=*=/=%= 这种快捷写法:  

1

2

3

4

5

intValue1 += intValue1 // 18

intValue1 -= intValue1 // 0

intValue1 *= intValue1 // 81

intValue1 /= intValue1 // 1

intValue1 %= intValue1 // 0

比较运算符

Go 语言支持以下几种常见的比较运算符: ><==>=<=!=

运算符 描述
== 检查两个值是否相等,如果相等返回 True 否则返回 False。
!= 检查两个值是否不相等,如果不相等返回 True 否则返回 False。
> 检查左边值是否大于右边值,如果是返回 True 否则返回 False。
>= 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。
< 检查左边值是否小于右边值,如果是返回 True 否则返回 False。
<= 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。

比较运算符运行的结果是布尔值 ,不同类型的值不能放在一起比较,否则会报编译出错,如下:

1

2

3

if intValue1 == intValue2 {

    fmt.Println("intValue1 和 intValue2 相等")

}

相同类型的值才可以:

1

2

3

if intValue1 < intValue3 {

    fmt.Println("intValue1 比 intValue3 小")

}

位运算符

位运算符对整数在内存中的二进制位进行操作,Go 语言支持以下这几种位运算符:

运算符 描述
& 参与运算的两数各对应的二进位相与。
(两位均为1才为1)
| 参与运算的两数各对应的二进位相或。
(两位有一个为1就为1)
^ 参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。
(两位不一样则为1)
<< 左移n位就是乘以2的n次方。
“a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。
>> 右移n位就是除以2的n次方。
“a>>b”是把a的各二进位全部右移b位。

一些简单的测试

1

2

3

4

5

6

7

var intValueBit uint8

intValueBit = 255

intValueBit = ^intValueBit // 按位取反

fmt.Println(intValueBit)   // 0

intValueBit = 1

intValueBit = intValueBit << 3 // 左移 3 位,相当于乘以 2^3 = 8

fmt.Println(intValueBit)       // 8

赋值运算符

运算符 描述
= 简单的赋值运算符,将一个表达式的值赋给一个左值
+= 相加后再赋值
-= 相减后再赋值
*= 相乘后再赋值
/= 相除后再赋值
%= 求余后再赋值
<<= 左移后赋值
>>= 右移后赋值
&= 按位与后赋值
|= 按位或后赋值
^= 按位异或后赋值

逻辑运算符

运算符 含义 描述
x && y 逻辑与运算符(AND) 如果 x 和 y 都是 true,则结果为 true,否则结果为 false
x || y 逻辑或运算符(OR) 如果 x 或 y 是 true,则结果为 true,否则结果为 false
!x 逻辑非运算符(NOT) 如果 x 为 true,则结果为 false,否则结果为 true


 

逻辑运算符计算的结果也是布尔值,通常我们可以组合使用逻辑运算符和比较运算符:

1

2

3

if intValue1 < intValue3 && intValue1 == 8 {

    fmt.Println("条件为真")

}

运算符优先级

上面介绍的 Go 语言运算符优先级如下所示(由上到下表示优先级从高到低,或者数字越大,优先级越高):

1

2

3

4

5

6

7

8

6      ^(按位取反) !

5      *  /  %  <<  >>  &  &^

4      +  -  |  ^(按位异或)

3      ==  !=  <  <=  >  >=

2      &&

1      ||

 

# ++ 或 -- 只能出现在语句中,不能用于表达式,故不参与优先级判断。 

回到顶部

六、浮点型与复数类型

Go语言支持两种浮点型数:float32float64。这两种浮点型数据格式遵循IEEE 754标准: float32 的浮点数的最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

打印浮点数时,可以使用fmt包配合动词%f,代码如下:

1

2

3

4

5

6

7

8

9

package main

import (

        "fmt"

        "math"

)

func main() {

        fmt.Printf("%f\n", math.Pi)

        fmt.Printf("%.2f\n", math.Pi)

}

定义一个浮点型变量的代码如下:

1

2

3

4

5

var floatValue1 float32

 

floatValue1 = 10

floatValue2 := 10.0 // 如果不加小数点,floatValue2 会被推导为整型而不是浮点型

floatValue3 := 1.1E-10

在实际开发中,应该尽可能地使用 float64 类型,因为 math 包中所有有关数学运算的函数都会要求接收这个类型。

浮点数的精度

浮点数不是一种精确的表达方式,因为二进制无法精确表示所有十进制小数,比如 0.10.7 这种,下面我们通过一个示例来给大家直观演示下:

1

2

3

floatValue4 := 0.1

floatValue5 := 0.7

floatValue6 := floatValue4 + floatValue5

浮点数的比较

浮点数支持通过算术运算符进行四则运算,也支持通过比较运算符进行比较,但是涉及到相等的比较除外,看起来相等的两个十进制浮点数,在底层转化为二进制时会丢失精度,

如果一定要判断相等,下面是一种替代的解决方案:

 

1

2

3

4

5

p := 0.00001

// 判断 floatValue1 与 floatValue2 是否相等

if math.Dim(float64(floatValue1), floatValue2) < p {

    fmt.Println("floatValue1 和 floatValue2 相等")

}

回到顶部

七、字符串及底层字符类型

字符串

在 Go 语言中,字符串是一种基本类型,默认是通过 UTF-8 编码的字符序列,当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节,比如中文编码通常需要 3 个字节。

声明和初始化

1

2

3

var str string         // 声明字符串变量

str = "Hello World"    // 变量初始化

str2 := "你好,学院君"   // 也可以同时进行声明和初始化

字符串转义符

转义符 含义
\r 回车符(返回行首)
\n 换行符(直接跳到下一行的同列位置)
\t 制表符
\' 单引号
\" 双引号
\\ 反斜杠

多行字符串

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

1

2

3

4

5

s1 := `第一行

第二行

第三行

`

fmt.Println(s1)

字符串的常用操作

方法 介绍
len(str) 求长度
+或fmt.Sprintf 拼接字符串
strings.Split 分割
strings.contains 判断是否包含
strings.HasPrefix,strings.HasSuffix 前缀/后缀判断
strings.Index(),strings.LastIndex() 子串出现的位置
strings.Join(a[]string, sep string) join操作

字符串连接

字符串连接只需要通过 + 连接符即可

1

2

str = str + ", 学院君"

str += ", 学院君" // 上述语句也可以简写为这样,效果完全一样

如果字符串长度较长,需要换行,则 + 连接符必须出现在上一行的末尾

1

2

str = str +

        ", 学院君"

字符串切片

1

2

3

4

5

6

7

str := "hello, world"

str1 := str[:5]  // 获取索引5(不含)之前的子串

str2 := str[7:]  // 获取索引7(含)之后的子串

str3 := str[0:5]  // 获取从索引0(含)到索引5(不含)之间的子串

fmt.Println("str1:", str1)

fmt.Println("str2:", str2)

fmt.Println("str3:", str3)

它是一个左闭右开的区间,比如上述 str[0:5] 对应到字符串元素的区间是 [0,5)str[:5] 对应的区间是 [0,5)(数组索引从 0 开始),str[7:] 对应的区间是 [7:len(str)](这是闭区间,是个例外,因为没有指定区间结尾)。

字符串遍历

字节数组的方式遍历:

1

2

3

4

5

6

str := "Hello, 世界"

n := len(str)

for i := 0; i < n; i++ {

    ch := str[i]    // 依据下标取字符串中的字符,ch 类型为 byte

    fmt.Println(i, ch)

}

Unicode 字符遍历:

1

2

3

4

str := "Hello, 世界"

for i, ch := range str {

    fmt.Println(i, ch)    // ch 的类型为 rune

}

将 Unicode 编码转化为可打印字符

1

2

3

4

str := "Hello, 世界"

for i, ch := range str {

    fmt.Println(i, string(ch))

} 

回到顶部

八、基本数据类型之间的转化

数值类型之间的转化

整型之间的转化

进行类型转化时只需要调用要转化的数据类型对应的函数即可:

1

2

3

v1 := uint(16)   // 初始化 v1 类型为 unit

v2 := int8(v1)   // 将 v1 转化为 int8 类型并赋值给 v2

v3 := uint16(v2) // 将 v2 转化为 uint16 类型并赋值给 v3

数值和布尔类型之间的转化

目前 Go 语言不支持将数值类型转化为布尔型,你需要自己根据需求去实现类似的转化。

字符串和其他基本类型之间的转化

将整型转化为字符串

整型数据可以通过 Unicode 字符集转化为对应的 UTF-8 编码的字符串:

1

2

3

4

5

6

7

8

9

10

11

12

13

v1 := 65

v2 := string(v1)  // v2 = A

 

v3 := 30028

v4 := string(v3)  // v4 = 界

 

 

// 还可以将 byte 数组或者 rune 数组转化为字符串,因为字符串底层就是通过这两个基本字符类型构建的

v1 := []byte{'h''e''l''l''o'}

v2 := string(v1) // v2 = hello

 

v3 := []rune{0x5b66, 0x9662, 0x541b}

v4 := string(v3) // v4 = 学院君

byteuint8 的别名,runeint32 的别名,所以也可以看做是整型数组和字符串之间的转化

strconv 包

Go 语言默认不支持将字符串类型强制转化为数值类型,即使字符串中包含数字也不行。

如果要实现更强大的基本数据类型与字符串之间的转化,可以使用 Go 官方 strconv 包提供的函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

v1 := "100"

v2, _ := strconv.Atoi(v1)  // 将字符串转化为整型,v2 = 100

 

v3 := 100

v4 := strconv.Itoa(v3)   // 将整型转化为字符串, v4 = "100"

 

v5 := "true"

v6, _ := strconv.ParseBool(v5)  // 将字符串转化为布尔型

v5 = strconv.FormatBool(v6)  // 将布尔值转化为字符串

 

v7 := "100"

v8, _ := strconv.ParseInt(v7, 10, 64)   // 将字符串转化为整型,第二个参数表示进制,第三个参数表示最大位数

v7 = strconv.FormatInt(v8, 10)   // 将整型转化为字符串,第二个参数表示进制

 

v9, _ := strconv.ParseUint(v7, 10, 64)   // 将字符串转化为无符号整型,参数含义同 ParseInt

v7 = strconv.FormatUint(v9, 10)  // 将字符串转化为无符号整型,参数含义同 FormatInt

 

v10 := "99.99"

v11, _ := strconv.ParseFloat(v10, 64)   // 将字符串转化为浮点型,第二个参数表示精度

v10 = strconv.FormatFloat(v11, 'E', -1, 64)

 

q := strconv.Quote("Hello, 世界")    // 为字符串加引号

q = strconv.QuoteToASCII("Hello, 世界")  // 将字符串转化为 ASCII 编码 

参考链接:https://pkg.go.dev/strconv  

 

相关文章
|
1月前
|
存储 编译器 Go
go语言中的变量、常量、数据类型
【11月更文挑战第3天】
36 9
|
1月前
|
存储 设计模式 安全
Go语言中的并发编程:从入门到精通###
本文深入探讨了Go语言中并发编程的核心概念与实践技巧,旨在帮助读者从理论到实战全面掌握Go的并发机制。不同于传统的技术文章摘要,本部分将通过一系列生动的案例和代码示例,直观展示Go语言如何优雅地处理并发任务,提升程序性能与响应速度。无论你是Go语言初学者还是有一定经验的开发者,都能在本文中找到实用的知识与灵感。 ###
|
1月前
|
Serverless Go
Go语言中的并发编程:从入门到精通
本文将深入探讨Go语言中并发编程的核心概念和实践,包括goroutine、channel以及sync包等。通过实例演示如何利用这些工具实现高效的并发处理,同时避免常见的陷阱和错误。
|
2月前
|
安全 Go 开发者
破译Go语言中的并发模式:从入门到精通
在这篇技术性文章中,我们将跳过常规的摘要模式,直接带你进入Go语言的并发世界。你将不会看到枯燥的介绍,而是一段代码的旅程,从Go的并发基础构建块(goroutine和channel)开始,到高级模式的实践应用,我们共同探索如何高效地使用Go来处理并发任务。准备好,让Go带你飞。
|
2月前
|
存储 安全 Go
Go语言切片:从入门到精通的深度探索###
本文深入浅出地剖析了Go语言中切片(Slice)这一核心概念,从其定义、内部结构、基本操作到高级特性与最佳实践,为读者提供了一个全面而深入的理解。通过对比数组,揭示切片的灵活性与高效性,并探讨其在并发编程中的应用优势。本文旨在帮助开发者更好地掌握切片,提升Go语言编程技能。 ###
|
3月前
|
存储 编译器 Go
Go to Learn Go之基本数据类型
Go to Learn Go之基本数据类型
37 0
|
4月前
|
Unix Go
Go从入门到放弃之时间操作
Go从入门到放弃之时间操作
|
4月前
|
机器学习/深度学习 移动开发 Linux
Go从入门到放弃之文件操作
Go从入门到放弃之文件操作
|
4月前
|
Java Go PHP
Go从入门到放弃之错误处理
Go从入门到放弃之错误处理
|
4月前
|
存储 Java Go
Go从入门到放弃之结构体(面向对象)
Go从入门到放弃之结构体(面向对象)