Go漫游笔记-02-类型

Go 是一门静态类型语言,不能在运行期改变变量的类型。
声明一个变量,首先也需要明确它的类型。
因此,我们先来看看 Go 支持的类型都有哪些?

布尔类型

1
var v bool        // true, false

数值类型

无符号整型

1
2
3
4
var v uint8       //  8 位,(0 到 255)
var v uint16 // 16 位,(0 到 65535)
var v uint32 // 32 位,(0 到 4294967295)
var v uint64 // 64 位,(0 到 18446744073709551615)

带符号整型

1
2
3
4
var v int8        //  8 位,(-128 到 127)
var v int16 // 16 位,(-32768 到 32767)
var v int32 // 32 位,(-2147483648 到 2147483647)
var v int64 // 64 位,(-9223372036854775808 到 9223372036854775807)

浮点数

1
2
var v float32     // 32 位
var v float64 // 64 位

复数

1
2
var v complex64   // 带 float32 实部和虚部的复数
var v complex128 // 带 float64 实部和虚部的复数

字符类型

1
2
var v byte        // 相当于 uint8
var v rune // 相当于 int32

平台相关的类型

1
2
var v uint        // 32 或 64 位
var v int // 32 或 64 位

需要注意的是:
除了 byterune 分别相当于 uint8int32 的别名以外,其它所有数值类型都被认为是不同的类型。
因此,当不同的数值类型混合在一个表达式或赋值操作中时,必须进行类型转换。
并且,intint32int64 也是不同的类型,即使它们在特定的硬件平台上大小可能是相同的。

字符串类型

1
2
var v string      // 字符串
v = "HelloWorld" // 字符串

数组类型

数组就是一组同类型的数据。
数组的长度是固定的,在定义后不可更改。

1
2
3
4
5
6
7
8
9
10
11
var v [2]string   // 字符串数组
a[0] = "Hello"
a[1] = "World"

var v [3][4]int32 // 二维数组

// 初始化
var v [2]int32 = [2]int{1, 2}

// 初始化的序列隐含了长度信息
var v = []int32{2, 3, 5}

切片类型( slice)

切片类似于一个动态数组,好比 Java 的 List

1
2
3
4
5
6
7
8
9
// 直接创建初始元素为 5 ,容量为 10 的切片
var v = make([]int32, 5, 10)

// 基于数组创建
var a = []int32{2, 3, 5, 7}
var s = a[1:3] // [3, 5]

// 尾部追加元素
append(s, 7, 12) // [3, 5, 7, 12]

Go 提供了 append 函数来完成 slice 的追加操作,但是并没有提供相应的 delete 函数。有可能是因为 delete 操作的实现会依赖于具体的应用场景(例如:删除中间元素和删除头尾的元素,二者实现起来肯定是不一样的),并没有一种完美的解决方案吧。

映射类型(map)

Key-Value 集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 声明
var personAge map[string] uint8
// 初始化
personAge = make(map[string] uint8)

// 元素赋值
personAge["franky"] = 17

// 查找元素
v, ok := personAge["franky"]
if ok {
// 找到后的处理
}

// 删除元素
delete(personAge, "franky")

结构类型(struct)

相当于“类(class)”。

1
2
3
4
5
6
7
8
9
10
type Person struct {
name string
age uint8
}

franky := Person{name: "franky", age: 17}

zhu := new(Person)
zhu.name = "zhu"
zhu.age = 18

指针类型

1
2
3
4
5
a, b := 1, 5
p := &a // p 是一个指针类型的变量
*p = 10 // 修改值, a = 10
p = &b // 指向新的对象
*p = a / *p // b = a / b = 10 / 5

函数类型

如果希望把函数当作参数传递,可以定义函数类型。

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
// 定义函数类型
type isFunc func(integer int32) bool

// 定义具体的函数
func isEven(integer int32) bool {
if integer%2 == 0 {
return true
}
return false
}

// 定义具体的函数
func isOdd(integer int32) bool {
return !isEven(integer)
}

// 函数当作参数传递
func filter(slice []int32, fn isFunc) []int32 {
var result []int32
for _, value := range slice {
if fn(value) {
result = append(result, value)
}
}
return result
}

func main() {
slice := []int32{0, 1, 2, 3, 4, 5}

// 传递具体的函数
even := filter(slice, isEven)
fmt.Println("偶数:", even)

// 传递具体的函数
odd := filter(slice, isOdd)
fmt.Println("奇数:", odd)
}

接口类型(interface)

接口是函数签名的集合。
在 Go 语言中,实现一个接口不需要进行显式的声明。
任何一个类型只要它实现了某个接口所声明的所有函数,那么,我们就可以认为它实现了这个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 定义接口
type Speaker interface {
speak()
}

type Person struct {
name string
}

// 实现接口的函数
func (p *Person) speak() {
fmt.Printf("%s say HelloWorld!", p.name)
}

func main() {
// 定义接口类型的变量
var s Speaker = &Person{name: "Franky"}
s.speak()
}

信道类型(Channel)

Channel 是 goroutine 间的通信方式。
Channel 是类型相关的。
也就是说,一个 Channel 只能传递一种类型的值,这个类型需要在声明时指定。

1
2
3
4
// 声明
var v chan int32
// 初始化
v := make(chan string)

由于 Channel 的使用,还需要依赖于更多的 Go 并发编程知识,因此这里只作简单了解,后面再深入学习。

Go 与 Java 的类型对比

Go Java
bool boolean
uint8 -
uint16 -
uint32 -
uint64 -
int8 byte
int16 short
int32 int
int64 long
float32 float
float64 double
complex64 -
complex128 -
byte -
rune -
uint -
int -
uintptr -
string *String
数组 *数组
slice *List
map *Map
struct *class
指针 -
func *方法
interface *interface
chan -

备注:- 表示无对应类型,* 表示类似。

总结

Go 内置的基础类型略多于 Java ,主要是因为其支持无符号数值类型的原因。
此外,Go 还内置了 mapslicechan 等高级类型。
这一点与 Java 通过类库的方式来支持,显然是不同的。