Golang - Part02 变量常量和数据类型

数据类型

整数

整数类型按照有/无符号划分,可分为有符号整数和无符号整数,二者按照大小划分,有 8 位、16 位、32 位和 64 位:

大小 8 位 16 位 32 位 64 位
有符号 int8 int16 int32 int64
无符号 uint8 uint16 uint32 uint64

此外,还有两种整数类型,分别是 int 和 uint,其大小与原生的有/无符号整数类型相同,都是 32 位或 64 位。

其中,int32 和 uint8 分别有类型别名是 rune 和 byte,二者可互换使用。需要注意的是,int 和 uint 都有别于大小明确的类型,也就是说,int 和 int32 是两种不同的类型,必须显示转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import "fmt"

var a int
var b int32
var c rune
var d byte
var e uint8

func main() {
fmt.Printf("a=%d type:%T\n", a, a)
fmt.Printf("b=%d type:%T\n", b, b)
fmt.Printf("c=%d type:%T\n", c, c)
fmt.Printf("d=%d type:%T\n", d, d)
fmt.Printf("e=%d type:%T\n", e, e)

if c == b {
fmt.Println("rune 类型是 int32 的类型别名,二者可以互换使用")
}

if d == e {
fmt.Println("byte 类型是 uint8 的类型别名,二者可以互换使用")
}
}
//a=0 type:int
//b=0 type:int32
//c=0 type:int32
//d=0 type:uint8
//e=0 type:uint8
//rune 类型是 int32 的类型别名,二者可以互换使用
//byte 类型是 uint8 的类型别名,二者可以互换使用

浮点数

浮点数类型有两种,分别是 float32 和 float64,大多数情况下,建议优先使用 float64,因为 float32 的运算容易产生误差。

1
2
3
4
5
6
7
8
9
10
var f float32
var g float64

func main() {
fmt.Printf("f=%g type:%T\n", f, f)
fmt.Printf("g=%g type:%T\n", g, g)
}

//f=0 type:float32
//g=0 type:float64

布尔

bool 型的值只有两种可能,true 和 false,在 Go 语言中,bool 型的零值是 false,布尔值无法隐式转换成数值 0 或 1,反之亦然。

1
2
3
4
5
6
var h bool

func main() {
fmt.Printf("h=%t type:%T\n", h, h)
}
//h=false type:bool

字符串

字符串是不可变的带双引号的字节序列,它可以包含任意数据,包括 0 值字节,不可变意味着多个字符串可以共享一块内存空间。

如图所示,同一块内存空间,包含字符串 s 、字符串 hello 和字符串 world。

image-20230326220136482

字符串操作:

  • len 函数

    内置的 len 函数返回字符串的字节数,并非字符的个数,UTF-8 的简体中文,一个字符占三个字节。

  • 下标访问字符

    通过下标访问字符串,可以得到第 i 个字符。

  • 子串生成

    子串生成操作 s[i:j] 产生一个新字符串,内容取自原字符串的字节,下标从 i (含边界值)开始,直到 j(不含边界值)。新字符串的大小是 j-i 个字节。

    需要注意的是,如果下标越界,或者 j 的值小于 i,将触发宕机异常。

    操作数 i 和 j 的默认值分别是 0 [字符串的起始位置]和 len(s) [字符串的终止位置],如果省略 i 或 j,或两者都省略,则取默认值。

  • 字符串连接

    加号(+)运算符连接两个字符串而生成一个新字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var i string

func main() {
fmt.Printf("i=%s type:%T\n", i, i)

i = "hello golang"
fmt.Printf("字符串 i 的长度:%d\n", len(i))
fmt.Printf("字符串 i 的第一个字符:%c\n", i[0])
j := i[0:5]
fmt.Printf("子字符串 j 的值:%s\n", j)
k := i[5:]
fmt.Printf("子字符串 k 的值:%s\n", k)
l := i[:5]
fmt.Printf("子字符串 l 的值:%s\n", l)
m := i[:]
fmt.Printf("子字符串 m 的值:%s\n", m)
n := "hello "
o := "world"
p := n + o
fmt.Printf("连接字符串 p 的值:%s\n", p)
}
//i= type:string
//字符串 i 的长度:12
//字符串 i 的第一个字符:h
//子字符串 j 的值:hello
//子字符串 k 的值: golang
//子字符串 l 的值:hello
//子字符串 m 的值:hello golang
//连接字符串 p 的值:hello world

变量

命名规则

Go 中命名规则是,名称以字母或下划线开头,后面可跟任意数量的字符、数字和下划线,字符区分大小写,名称本身没有长度限制,但是 Go 的编程风格倾向于使用短名称,特别是局部变量,Go 中有 25 个关键字,这些关键字不可用来命名。

Go 语言 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

声明变量

  • 声明变量的通用形式

    1
    var name type = expression
  • 声明变量的省略形式

    1
    2
    var totalScore int
    var totalScore2 = 678

    省略形式声明变量,类型和表达式可以省略其一,但是不能都省略。省略表达式,它的初始值是类型的零值,省略类型,它的初始化表达式决定变量的类型。

  • 声明变量列表

    1
    2
    3
    var a, b, c int
    var d, e, f int = 1, 2, 3
    var g, h, i = 3.14, "hello", true

    声明变量列表,省略类型,以初始化表达式决定变量的类型,允许声明多个不同类型的变量。

  • 调用有返回值函数的形式声明变量

    1
    2
    3
    4
    5
    var myname = name("lucy")
    func name(name string) string {
    var str string = "My name is " + name
    return str
    }

声明短变量

在函数中,短变量声明用来声明和初始化局部变量。

  • 声明一个整数类型的局部变量:

    1
    totalScore := 123
  • 声明一个短变量列表:

    1
    x, y := 1, 2

注意:短变量声明,左侧必须至少声明一个新变量。

指针

指针的值是一个变量的地址。一个指针代表一个变量的值所保存的位置。指针可以在不知道变量名的情况下,读取和更新变量的值。

1
var x int

声明一个整型的变量 x,&x 获取一个指向变量 x 的指针,它的类型是整型的指针类型(*int)

1
2
3
4
5
6
7
z := 3
p := &z
fmt.Printf("z=%d\n", z)
fmt.Printf("p=%p\n", p)
*p = 4
fmt.Printf("z=%d\n", z)
fmt.Printf("p=%p\n", p)

p 是指向 z 的指针,是 z 的地址,它的类型是整型的指针类型(*int),*p 是变量 z 的值,是变量 z 的别名,可以读取和更新变量 z。

指针类型的零值是 nil,指针是可比较的,两个指针只有指向同一个变量,或者都是 nil 的情况下才相等。

常量

常量是一种表达式,常量的计算可以在编译时完成,如果有错误,在编译时就会报错,常量的值不可以修改。

声明常量

1
2
3
4
5
6
7
8
9
10
11
12

const name string = "golang"
const PI = 3.14

func main() {
fmt.Printf("name = %s type:%T\n", name, name)
fmt.Printf("PI = %g type:%T\n", PI, PI)
}

// name = golang type:string
// PI = 3.14 type:float64

声明一组常量,每个常量类型可以不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

const (
x = 1
y = "hello"
z = true
)

func main() {
fmt.Printf("x = %d type:%T\n", x, x)
fmt.Printf("y = %s type:%T\n", y, y)
fmt.Printf("z = %t type:%T\n", z, z)
}

//x = 1 type:int
//y = hello type:string
//z = true type:bool

声明一组常量,除了第一个常量之外,其他常量都可以省略表达式,其他常量会复用其前面一个常量的类型和表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const (
a = 1
b
c = 2
d
)

func main() {
fmt.Printf("a = %d type:%T\n", a, a)
fmt.Printf("b = %d type:%T\n", b, b)
fmt.Printf("c = %d type:%T\n", c, c)
fmt.Printf("d = %d type:%T\n", d, d)
}

//a = 1 type:int
//b = 1 type:int
//c = 2 type:int
//d = 2 type:int

常量生成器 iota

声明一组常量,可以使用常量生成器 iota,它可以不用逐个常量显示指定类型和赋值表达式,常量声明中,iota 从 0 开始取值,后续常量如果没有显示指定类型和赋值表达式,其值是其前面一个常量的值加 1。直到遇到赋值常量停止加 1,后续如果再遇到赋值 iota 的常量,则继续逐个加 1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const (
Sunday int = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)

const (
aa int = iota
bb
cc
dd = 10
ee
ff = iota
gg
hh
)

func main() {
fmt.Printf("Sunday = %d type:%T\n", Sunday, Sunday)
fmt.Printf("Monday = %d type:%T\n", Monday, Monday)
fmt.Printf("Tuesday = %d type:%T\n", Tuesday, Tuesday)
fmt.Printf("Wednesday = %d type:%T\n", Wednesday, Wednesday)
fmt.Printf("Thursday = %d type:%T\n", Thursday, Tuesday)
fmt.Printf("Friday = %d type:%T\n", Friday, Friday)
fmt.Printf("Saturday = %d type:%T\n", Saturday, Saturday)
fmt.Printf("aa = %d type:%T\n", aa, aa)
fmt.Printf("bb = %d type:%T\n", bb, bb)
fmt.Printf("cc = %d type:%T\n", cc, cc)
fmt.Printf("dd = %d type:%T\n", dd, dd)
fmt.Printf("ee = %d type:%T\n", ee, ee)
fmt.Printf("ff= %d type:%T\n", ff, ff)
fmt.Printf("gg = %d type:%T\n", gg, gg)
fmt.Printf("hh = %d type:%T\n", hh, hh)
}


//Sunday = 0 type:int
//Monday = 1 type:int
//Tuesday = 2 type:int
//Wednesday = 3 type:int
//Thursday = 4 type:int
//Friday = 5 type:int
//Saturday = 6 type:int
//aa = 0 type:int
//bb = 1 type:int
//cc = 2 type:int
//dd = 10 type:int
//ee = 10 type:int
//ff= 5 type:int
//gg = 6 type:int
//hh = 7 type:int

无类型常量

1
2
3
4
5
6
7
8
9
10
11
const username, age = "lucy", 17
const user = username

func main() {
fmt.Printf("username = %s, age = %d\n", username, age)
fmt.Printf("user = %s\n", user)
}

//username = lucy, age = 17
//user = lucy