数据类型和控制结构

数据类型和控制结构

数据类型 #

常量和变量 #

变量:
var varName dataType [ = value ]
var varName = value
varName := value (只能在函数或方法内使用)

常量: 布尔型、字符串型和数值型。
const name = value

基本数据类型 #

类型
整型 byte int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
浮点型 float32 float64
复数型 complex64 complex128
字符 rune
字符串型 string
布尔型 bool

字符串类型 #

1、len() 函数求的是字符串字节的长度;

len("H你") = 4

2、Go内置两种字符类型:一种是byte的字节类类型(uint8的别名),另一种是表示Unicode编码的字符rune。 rune在Go内部是int32类型的别名,占用4个字节。Go语言默认的字符编码就是UTF-8类型的,如果需要特殊的编码转换,则使用Unicode/UTF-8标准包。

复合数据类型 #

指针 #

Go中的指针及与指针对指针的操作主要有以下三种:
一普通的指针类型,例如 var intptr *T,定义一个T类型指针变量
二内置类型uintptr,本质是一个无符号的整型,它的长度是跟平台相关的,是一个能足够容纳指针位数大小的整数类型,可进行指针运算。
三是unsafe包提供的Pointer,表示可以指向任意类型的指针。

uintptr

声明和初始化

func main() {
	a := 10
	b := &a
	fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
	fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
	fmt.Println(&b)                    // 0xc00000e018
}

数组 #

声明和初始化

var arr [2]int
var a = [3]int{1, 2, 3}
a := [...]int{1, 2, 3}
a := [3]int{1:1, 2:3}
a := [...]int{1:1, 2:3}

说明

数组是值类型,赋值和传参会复制整个数组。因此改变副本的值,不会改变本身的值。

切片 #

声明和初始化

1定义切片类型
var a []int    //nil
var b = []int{}
var c = []int{1, 2}

2由数组创建
a := [5]int{1, 2, 3, 4, 5}
s := a[1:3]  // s := a[low:high],左闭右开

3make创建
var a = make([]int, 2, 10)

说明

切片是一个引用类型,它是基于数组类型做的一层封装,它的内部结构包含地址长度容量

map #

声明和初始化

1定义map类型
var a map[int]string  //nil
var b = map[int]string{1:"1", 2:"2"}

2make创建
var m = make(map[string]int, 2, 10)

说明

map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。

特别用法

//判断某个键是否存在
value, ok := map[key]

struct #

声明和初始化

1匿名结构体
struct {
    FieldName FieldType
}
//在定义的时候初始化,可以赋值给变量

2自定义struct类型
type TypeName struct {
    FieldName FieldType
}

chan #

声明和初始化

1定义chan类型
var a chan int
var b chan<- int //单向写通道
var c <-chan int //单向读通道

2make创建
var c = make(chan int)
var c = make(chan int, 10)    //10个缓冲的通道

说明

1、无缓冲的通道既可以用于通信,也可用于两个goroutine的同步;有缓冲的通道主要用于通信;
2、若close(chan)后,则写数据会panic,而读数据会返回通道元素的零值;可通过comma, ok表达式判断chan是否关闭;
3、向缓冲区已满的通道写数据会协程阻塞,读取没数据(未关闭)的通道也会协程阻塞;
4、向未初始化的通道读写数据都会造成协程的永久阻塞;
5、重复关闭通道会导致panic。

make和new的区别:
1、make和new都是用来申请内存的;
2、new很少用,一般用来给基本数据类型申请内存,string、int等返回的是对应类型的指针(*string, *int);
3、make是用来给slice、map、chan申请内存的,name函数返回的是对应这三个类型本身。

控制结构 #

if语句 #

if x:= f(); x < y {	//初始化语句中声明变量x
    return x
} else if x > z {
    return z
} else {
    return y
}

switch语句 #

switch i := f(); i {
case a:
    fmt.Println("1")
case b:
    fmt.Println("2")
    fallthrough	//强制执行下一个case语句,不再判断下一个case语句是否满足条件
case c:
    fmt.Println("3")
default:
    fmt.Println("bye")
}

for语句 #

1类似于C循环中的for语句
for init; condition; post {}

2类似C的while语句
for condition {}

3类似于C的while(1)死循环
for {}

4对数组切片字符串map和通道的访问
for k, v := range Type {}

标签和跳转 #

1使用标签(Label)来标识一个语句的位置
Label: Statement
2gotobreakcontinue可以单独使用也可以和标签配合使用跳到指定位置
3return用于函数和方法的退出

例如:
if n%2 == 1 {
    goto L1
}
for n > 0 {
    f()
    n--
L1:
    f()
    n--
}