基本类型
布尔型
var b bool
b = true
fmt.Printf("b is of type %t\n", b)
e := bool(true)
fmt.Printf("e is of type %t\n", e)
- 长度:1字节
- 取值范围:true/false
- 只能使用true/false值,不能使用数字代替布尔值
整形 int/uint
package main
import "fmt"
func main() {
// n 是一个长度为 10 的数组
var n [10]int
var i,j int
/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}
/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j] )
}
}
- int/uint
- 根据平台可能为32/64位
8位整型 int8/uint8
u8 := []uint8{98, 99}
a := byte(255) //11111111 这是byte的极限, 因为 a := byte(256)//越界报错, 0~255正好256个数,不能再高了
b := uint8(255) //11111111 这是uint8的极限,因为 c := uint8(256)//越界报错,0~255正好256个数,不能再高了
c := int8(127) //01111111 这是int8的极限, 因为 b := int8(128)//越界报错, 0~127正好128个数,所以int8的极限只是256的一半
d := int8(a) //11111111 打印出来则是-0000001,int8(128)、int8(255)、int8(byte(255))都报错越界,因为int极限是127,但是却可以写:int8(a),第一位拿来当符号了
e := int8(c) //01111111 打印出来还是01111111
fmt.Printf("%08b %d \n", a, a)
fmt.Printf("%08b %d \n", b, b)
fmt.Printf("%08b %d \n", c, c)
fmt.Printf("%08b %d \n", d, d)
fmt.Printf("%08b %d \n", e, e)
- int8/uint8
- 长度:1字节
- 取值范围:-128
127/0255
字节型 byte
// 这里不能写成 b := []byte{"Golang"},这里是利用类型转换。
b := []byte("Golang")
c := []byte("go")
d := []byte("Go")
println(b,c,d)
- byte(uint8别名)
基本处理函数
Contains()
返回是否包含子切片Count()
子切片非重叠实例的数量Map()
函数,将byte 转化为Unicode,然后进行替换Repeat()
将切片复制count此,返回这个新的切片Replace()
将切片中的一部分 替换为另外的一部分Runes()
将 S 转化为对应的 UTF-8 编码的字节序列,并且返回对应的Unicode 切片Join()
函数,将子字节切片连接到一起。
可以参考下面列子来理解上面7个方法,例子 byte.go
package main
import (
"bytes"
"fmt"
)
func main() {
// 这里不能写成 b := []byte{"Golang"},这里是利用类型转换。
b := []byte("Golang")
subslice1 := []byte("go")
subslice2 := []byte("Go")
// func Contains(b, subslice [] byte) bool
// 检查字节切片b ,是否包含子字节切片 subslice
fmt.Println(bytes.Contains(b, subslice1))
fmt.Println(bytes.Contains(b, subslice2))
s2 := []byte("同学们,上午好")
m := func(r rune) rune {
if r == '上' {
r = '下'
}
return r
}
fmt.Println(string(s2))
// func Map(mapping func(r rune) rune, s []byte) []byte
// Map函数: 首先将 s 转化为 UTF-8编码的字符序列,
// 然后使用 mapping 将每个Unicode字符映射为对应的字符,
// 最后将结果保存在一个新的字节切片中。
fmt.Println(string(bytes.Map(m, s2)))
s3 := []byte("google")
old := []byte("o")
//这里 new 是一个字节切片,不是关键字了
new := []byte("oo")
n := 1
// func Replace(s, old, new []byte, n int) []byte
//返回字节切片 S 的一个副本, 并且将前n个不重叠的子切片 old 替换为 new,如果n < 0 那么不限制替换的数量
fmt.Println(string(bytes.Replace(s3, old, new, n)))
fmt.Println(string(bytes.Replace(s3, old, new, -1)))
// 将字节切片 转化为对应的 UTF-8编码的字节序列,并且返回对应的 Unicode 切片。
s4 := []byte("中华人民共和国")
r1 := bytes.Runes(s4)
// func Runes(b []byte) []rune
fmt.Println(string(s4), len(s4)) // 字节切片的长度
fmt.Println(string(r1), len(r1)) // rune 切片的长度
// 字节切片 的每个元素,依旧是字节切片。
s5 := [][]byte{
[]byte("你好"),
[]byte("世界"), //这里的逗号,必不可少
}
sep := []byte(",")
// func Join(s [][]byte, sep []byte) []byte
// 用字节切片 sep 吧 s中的每个字节切片连接成一个,并且返回.
fmt.Println(string(bytes.Join(s5, sep)))
}
16位整型 int16/uint16
- int16/uint16
- 长度:2字节
- 取值范围:-32768
32767/065535
32位整型 int32(别名rune)/uint32
- int32(别名rune)/uint32
- 长度:4字节
- 取值范围:-2^32/2
2^32/2-1/02^32-1
64位整型 int64/uint64
- int64/uint64
- 长度:8字节
- 取值范围:-2^64/2
2^64/2-1/02^64-1
浮点型 float32/float64
package main
import "fmt"
func main() {
var x float64
x = 20.0
fmt.Println(x)
fmt.Printf("x is of type %T\n", x)
a := float64(20.0)
b := 42
fmt.Println(a)
fmt.Println(b)
fmt.Printf("a is of type %T\n", a)
fmt.Printf("b is of type %T\n", b)
}
实例:float.go
- float32/float64
- 长度:4/8字节
- 小数位:精确到 7/15 位小数
复数 complex64/complex128
- complex64/complex128
- 长度:8/16
指针整数型 uintptr
用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被回收。
- uintptr
- 保存指正的 32 位或者 64 位整数型
// 示例:通过指针修改结构体字段
package main
import (
"fmt"
"unsafe"
)
func main() {
s := struct {
a byte
b byte
c byte
d int64
}{0, 0, 0, 0}
// 将结构体指针转换为通用指针
p := unsafe.Pointer(&s)
// 保存结构体的地址备用(偏移量为 0)
up0 := uintptr(p)
// 将通用指针转换为 byte 型指针
pb := (*byte)(p)
// 给转换后的指针赋值
*pb = 10
// 结构体内容跟着改变
fmt.Println(s)
// 偏移到第 2 个字段
up := up0 + unsafe.Offsetof(s.b)
// 将偏移后的地址转换为通用指针
p = unsafe.Pointer(up)
// 将通用指针转换为 byte 型指针
pb = (*byte)(p)
// 给转换后的指针赋值
*pb = 20
// 结构体内容跟着改变
fmt.Println(s)
// 偏移到第 3 个字段
up = up0 + unsafe.Offsetof(s.c)
// 将偏移后的地址转换为通用指针
p = unsafe.Pointer(up)
// 将通用指针转换为 byte 型指针
pb = (*byte)(p)
// 给转换后的指针赋值
*pb = 30
// 结构体内容跟着改变
fmt.Println(s)
// 偏移到第 4 个字段
up = up0 + unsafe.Offsetof(s.d)
// 将偏移后的地址转换为通用指针
p = unsafe.Pointer(up)
// 将通用指针转换为 int64 型指针
pi := (*int64)(p)
// 给转换后的指针赋值
*pi = 40
// 结构体内容跟着改变
fmt.Println(s)
}
数组类型 array
数组声明语法
var variable_name [SIZE]variable_type
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。下面是一个简单的对数组操作的例子array.go
package main
import "fmt"
func main() {
// 声明一个长度为5的整数数组
// 一旦数组被声明了,那么它的数据类型跟长度都不能再被改变。
var array1 [5]int
fmt.Printf("array1: %d\n\n", array1)
// 声明一个长度为5的整数数组
// 初始化每个元素
array2 := [5]int{12, 123, 1234, 12345, 123456}
array2[1] = 5000
fmt.Printf("array2: %d\n\n", array2[1])
// n 是一个长度为 10 的数组
var n [10]int
var i,j int
/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}
/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j] )
}
/* 数组 - 5 行 2 列*/
var a = [5][2]int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
var e, f int
/* 输出数组元素 */
for e = 0; e < 5; e++ {
for f = 0; f < 2; f++ {
fmt.Printf("a[%d][%d] = %d\n", e,f, a[e][f] )
}
}
}
初始化数组中 {} 中的元素个数不能大于 [] 中的数字。如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:
var array1 = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。例如:
float32 salary = array1[9]
以上实例读取了数组array1
第10
个元素的值。
多维数组,下面例子
// 三行四列
a = [3][4]int{
{0, 1, 2, 3} , /* 第一行索引为 0 */
{4, 5, 6, 7} , /* 第二行索引为 1 */
{8, 9, 10, 11} /* 第三行索引为 2 */
}
访问多维数组
// 访问第2行第3列
int val = a[2][3]
结构类型 struct
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
// 结构体字段使用点号来访问。
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
// 结构体字段可以通过结构体指针来访问。
e := Vertex{1, 2}
p := &e
p.X = 1e9
fmt.Println(e)
var (
v1 = Vertex{1, 2} // 类型为 Vertex
v2 = Vertex{X: 1} // Y:0 被省略
v3 = Vertex{} // X:0 和 Y:0
p = &Vertex{1, 2} // 类型为 *Vertex , 特殊的前缀 & 返回一个指向结构体的指针
)
fmt.Println(v1, p, v2, v3)
}
简单的结构体
type T struct {a, b int}
结构体里的字段都有 名字,像 field1
、field2
等,如果字段在代码中从来也不会被用到,那么可以命名它为 _
。上面简单的结构体定义,下面调用方法:
var s T
s.a = 5
s.b = 8
数组可以看作是一种结构体类型,不过它使用下标而不是具名的字段。
var t *T
t = new(T)
上面简单的管用语句方法t := new(T)
,变量 t
是一个指向 T
的指针,此时结构体字段的值是它们所属类型的零值。
声明 var t T
也会给 t
分配内存,并零值化内存,但是这个时候 t
是类型T
。在这两种方式中,t
通常被称做类型 T
的一个实例(instance)或对象(object)。
一个非常简单的例子structs_fields.go运行例子查看结果:
→ go run test/structs_fields.go
The int is: 10
The float is: 15.500000
The string is: Chris
&{10 15.5 Chris}
使用 new
字符串类型 string
var str string //声明一个字符串
str = "Go lang" //赋值
ch :=str[0] //获取第一个字符
len :=len(str) //字符串的长度,len是内置函数 ,len=5
len函数是Go中内置函数,不引入strings包即可使用。len(string)返回的是字符串的字节数。len函数所支持的入参类型如下:
- len(Array) 数组的元素个数
- len(*Array) 数组指针中的元素个数,如果入参为nil则返回0
- len(Slice) 数组切片中元素个数,如果入参为nil则返回0
- len(map) 字典中元素个数,如果入参为nil则返回0
- len(Channel) Channel buffer队列中元素个数
接口类型 inteface
package main
import (
"fmt"
"math"
)
/* 定义一个 interface */
type shape interface {
area() float64
}
/* 定义一个 circle */
type circle struct {
x,y,radius float64
}
/* 定义一个 rectangle */
type rectangle struct {
width, height float64
}
/* 定义一个circle方法 (实现 shape.area())*/
func(circle circle) area() float64 {
return math.Pi * circle.radius * circle.radius
}
/* 定义一个rectangle方法 (实现 shape.area())*/
func(rect rectangle) area() float64 {
return rect.width * rect.height
}
/* 定义一个shape的方法*/
func getArea(shape shape) float64 {
return shape.area()
}
func main() {
circle := circle{x:0,y:0,radius:5}
rectangle := rectangle {width:10, height:5}
fmt.Printf("circle area: %f\n",getArea(circle))
fmt.Printf("rectangle area: %f\n",getArea(rectangle))
}
实例:inteface.go
函数类型 func
package main
import "fmt"
type functinTyoe func(int, int) // 声明了一个函数类型
func (f functinTyoe)Serve() {
fmt.Println("serve2")
}
func serve(int,int) {
fmt.Println("serve1")
}
func main() {
a := functinTyoe(serve)
a(1,2)
a.Serve()
}
实例:func.go
引用类型 func
切片
是一种可以动态数组,可以按我们的希望增长和收缩。
- slice
Map
是一种无序的键值对的集合。是一种集合,所以我们可以像迭代数组和 slice 那样迭代它。
- map
// 通过 make 来创建
dict := make(map[string]int)
// 通过字面值创建
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
// 给 map 赋值就是指定合法类型的键,然后把值赋给键
colors := map[string]string{}
colors["Red"] = "#da1337"
// 不初始化 map , 就会创建一个 nil map。nil map 不能用来存放键值对,否则会报运行时错误
var colors map[string]string
colors["Red"] = "#da1337"
// Runtime Error:
// panic: runtime error: assignment to entry in nil map
//选择是只返回值,然后判断是否是零值来确定键是否存在。
value := colors["Blue"]
if value != "" {
fmt.Println(value)
}
在函数间传递 map 不是传递 map 的拷贝。所以如果我们在函数中改变了 map,那么所有引用 map 的地方都会改变
func main() {
colors := map[string]string{
"AliceBlue": "#f0f8ff",
"Coral": "#ff7F50",
"DarkGray": "#a9a9a9",
"ForestGreen": "#228b22",
}
for key, value := range colors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
removeColor(colors, "Coral")
for key, value := range colors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
}
func removeColor(colors map[string]string, key string) {
delete(colors, key)
}
通道
- chan
类型别名
type (
byte int8
rune init32
文本 string
)
var b 文本
b = "别名类型,可以是中文!"